import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
#The inputs to this node will be stored as a list in the IN variables.
OUT = []
def tolist(obj):
if hasattr(obj, "__iter__"):
return obj
else:
return [obj]
items = tolist(IN[0])
splittingItems = tolist(IN[1])
outList = []
for splitter in splittingItems:
i = 0
while i < len(items):
if items[i] == splitter:
items[i] = [items[i]]
i += 1
else:
i += 1
OUT = items
very close, I am expecting to slice the list when those strings appear, but the subgroup would be comprised between the string item found until the next found in the list, the subgroups would be what I marked in red. Many thanks
in designscript I did it like this, but I need to do it in Python because it kills all memory RAM when list output results over million items
#slice list by key
t2=key list
t3=list
slicedbykeytag = DSCore.List.Slice(t3, DSCore.List.AddItemToFront(0, t2), DSCore.List.AddItemToEnd(DSCore.List.Count(t3), t2), 1);
I tried to write this code in python node loading the designscript DSCore but I get a warning:
Warning: IronPythonEvaluator.EvaluateIronPythonScript operation failed.
Traceback (most recent call last):
File "<string>", line 134, in <module>
TypeError: expected Nullable[int], got ArrayList
I tried that as well but it feeds indices that are previously generated, and I got a warning
# Load the Python Standard and DesignScript Libraries
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# The inputs to this node will be stored as a list in the IN variables.
indices = IN[1]
input = IN[0]
splitbykey = []
reduce(lambda x, y: splitbykey.append(input[x:y]) or y, indices + [len(input)], 0)
OUT= splitbykey
There’s probably a more clever way to write this, but it should work:
# Enable Python support and load DesignScript library
import clr
# The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN
def tolist(obj):
if hasattr(obj, "__iter__"):
return obj
else:
return [obj]
def split_at_values(items, values):
ot = []
items = tolist(items)
for index,item in enumerate(items):
check = item in values
if check and index==0:
ot = [item]
new_items = items[1:]
break
elif check and index > 0:
ot = items[:index+1]
new_items = items[index+1:]
break
else:
new_items = [item]
return ot, new_items
def split_list(items, values):
ot = []
i = 0
while items and i < 100:
i += 1
check = [x for x in values if x in items]
if check:
split = split_at_values(items, values)
ot.append(split[0])
items = split[1]
else:
ot.append(items)
break
return ot
items = tolist(IN[0])
splitting_items = tolist(IN[1])
# Assign output
OUT = split_list(items, splitting_items)
indices = IN[1]
list = IN[0]
from itertools import izip, chain
def partition(list, indices):
pairs = izip(chain([0], indices), chain(indices, [None]))
return (list[i:j] for i, j in pairs)
OUT = partition(list, indices)
well this last script is not doing all the process I wanted because I have to write more python code to feed the input of indexes, which match with a list of search inputs wanted, so in reality my code is quite longer but I would like it shortened, but still learning
def group(lst,criteria):
out = []
it = iter(lst)
for i in lst:
if next(it) in criteria: out.append([i])
else: out[-1].append(i)
return out
OUT = group(IN[0],IN[1])
If I’m reading this right, it only works for groups of 2. However, I used your idea of using iter:
def split_list(items, values):
ot = []
idx = [i for i,v in enumerate(items) if v in values]+[None]
it = iter(idx)
next(it)
return [items[i:next(it)] for j,i in enumerate(idx) if j != len(idx)-1]
I don’t have Revit readily available, so here’s a screenshot in the stock Python shell:
Actually I guess since I’m using enumerate the iter is superfluous. Also forgot to take out the ot from before I put in the list comprehension as the return value.
def split_list(items, values):
idx = [i for i,v in enumerate(items) if v in values]+[None]
return [items[i:idx[j+1]] for j,i in enumerate(idx) if j != len(idx)-1]
it seems it works great, but for some reason I noticed that the first sublist generated disappeared, and the rest of the original list seems same, I mean if your original list does not start with the key, you lose the subgroup with items until you get the first key, so I would have to start the original list with a key to do not lose items
def group(lst,criteria):
out = []
it = iter(lst)
for i in lst:
if next(it) in criteria:
out.append([i])
else:
try: out[-1].append(i)
except: out.append([i])
return out
import sys
def r_split(lst):
out = []
for i in lst:
out.append(i)
if i in s_values:
yield out
out = []
if out:
yield out
input_lst = IN[0]
s_values = IN[1]
OUT = list(r_split(input_lst))
recursive function
import sys
def r_split2(lst):
try:
min_idx = min(lst.index(x) for x in s_values if lst.count(x) > 0)
except Exception as ex:
return [lst] if lst else []
out, rest = lst[:min_idx + 1], lst[min_idx + 1:]
return [out] + r_split2(rest)
input_lst = IN[0]
s_values = IN[1]
OUT = r_split2(input_lst)
hello, it looks amazing many thanks, but it is not doing what I was expecting. The original list is flatten and the sublists are created each time the key list is found on the list, so first item of the sublists must be a key of the list but it is not happening here