[Python] List processing algorithm out of ideas

I’m not sure if I exactly got what you want, but if I’m not mistaken you can achieve same result with very simpler algorithm:

import rhinoscriptsyntax as rs
yCoordinates = []
for line in lines:
    yCoordinates.append(rs.CurveStartPoint(line).Y)
    yCoordinates.append(rs.CurveEndPoint(line).Y)
maxY = max(yCoordinates)
minY = min(yCoordinates)
sumY = abs(minY-maxY)


IVELIN PEYCHEV.gh (13.6 KB)

Hi, can there be gaps between lines on the same X? Can they overlap but with different lengths? Can they be exact duplicates?

Thanks Mahdiyar,

But I know how to find the items with equal X coordinates and sum them up, I need the lists though with equal number of items.

How about using zip(l1,l2) to combine your two lists into types? Would that help you keep track of paired values?

Yes I tried that, but how to combine the arrays such that zip[0] stays the same and zip[1] is a sum of all items that have equal zip[0]?

This is the main question.

I tried something with 4-5 levels of for and if loops and ended up with lots of duplicates.

for the practical case,

Is there a way to find all lines with X==i, Y = 0 and Z = 0 and sum them up?
RhinoCommon, Grasshopper?

I think I found a solution here:

But I still get one phantom item more in one of the lists:

import rhinoscriptsyntax as rs
from ghpythonlib.treehelpers import list_to_tree

from collections import Counter
A = []
c = Counter()
zlst = []
for i in range(len(x)):
    zlst.append([str(y[i].X),round(x[i],0)])


for j,k in zlst:
    c.update({j:k})

for l in range(len(zlst)):
    A.append(zlst[l])

a,b = zip(*A)

AA = list(set(a))
BB = list(set(b))

#len(AA) = 221
#len(BB) = 222

I was thinking of this data structure:

from collections import defaultdict
lines = defaultdict(list)
for tup in zip(L1,L2):
    lines[tup[0]].append(tup)

Based on the practical case I’d try:

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino as R

line_guids = rs.GetObjects('select lines')

# get line geometry
lines = []
for lg in line_guids:
    lines.append(rs.coerceline(lg))

# dict to hold list of lines keyed on x coordinate
line_lists = {}
# populate the dict
for line in lines:
    if line.FromX not in line_lists:  # should probably test x to some window
        line_lists[line.FromX] = [line]
    else:
        line_lists[line.FromX].append(line)

# loop through the line_lists and do calcs
for x_start, line_list in line_lists.items():
    sum = 0
    count = len(line_list)
    for line in line_list:
        sum += line.Length
    print('x coord of {} has {} lines with summed length of {}'.format(x_start, count, sum))

Output:

x coord of 0.0 has 3 lines with summed length of 20.9950916265
x coord of -6.61721090246 has 1 lines with summed length of 5.94563031763
x coord of -3.77186291026 has 3 lines with summed length of 14.1364263773

Input:

image

Should probably think about the x coordinate key precision though. Also it doesn’t use list indices, if that is a requirement.

1 Like

Or defaultdict(set) to remove duplicates. Then you can use for xval, line in lines.iteritems() to iterate over your list / set

1 Like

Yes, that is a requirement, since the values in L1 could be scrambled.

Thank you @nathancoatney, @Dancergraham ,

I need to think through the ideas and how I can apply them.

Plus that thread in stackoverflow seems similar to mine. I need to see if I can combine all ideas.

What I mean is that it doesn’t correlate indexes, as it works with the geometry. One could do the same with indexes, just the comparing would be different, so you would have:

L1 = [0,1,2,3,4,5,6,7,7,8,8,8,9,10,10]
L2 = [12,412,51,523,52,54,65,74,35,22,14,1,3,76,159]

L1_indicies = {}
for i, l in enumerate(L1):
    if l not in L1_indicies:
        L1_indicies[l] = [i]
    else:
        L1_indicies[l].append(i)

print(L1_indicies)

L1a = []
L2a = []

for value, indices in L1_indicies.items():
    sum = 0
    for i in indices:
        sum += L2[i]
    L1a.append(value)
    L2a.append(sum)
    
print(L1a)
print(L2a)

That stackoverflow link has more pythonic ways to do the same it looks like.

1 Like

You’re welcome :slight_smile:
For the next step it may be helpful to sort the lines by y value, eg:

for xval,listt in lines.iteritems():
  print(sorted(listt,key = lambda x: x[1]))
1 Like

I added a few lines and it’s now useful in my case:


import collections



L1_indicies = {}

for i, l in enumerate(L1):
    if l not in L1_indicies:
        L1_indicies[l] = [i]
    else:
        L1_indicies[l].append(i)

print(L1_indicies)

L1a = []
L2a = []

for value, indices in L1_indicies.items():
    sum = 0
    for i in indices:
        sum += L2[i]
    L1a.append(value)
    L2a.append(sum)
    
print(L1a)
print(L2a)

a = []
b = []

d = dict(zip(L1a,L2a))
od = collections.OrderedDict(sorted(d.items()))

for key, value in od.iteritems():
    temp = [key,value]
    a.append(temp[0])
    b.append(temp[1])

Thanks Graham,

Your examples are a bit advanced. I don’t know in which cases I have to use enumerate let alone lambda :slight_smile:

Thanks anyways. Some day I’ll understand them better.

1 Like

Glad it helped.

Maybe slightly more compact to avoid the zipping and the OrderedDict, sort the keys of of the dict instead of looping through the items:

for key in sorted(L1_indicies.keys()):
    indices = L1_indicies[key]
    sum = 0
    for i in indices:
        sum += L2[i]
    L1a.append(key)
    L2a.append(sum)

I think that will give you two lists in sorted order, which I think is the same as your a and b lists, and should save quite a bit of overhead if that is important.

1 Like

:smiley: I’ll dial it back a bit !

Simple is better than complex.

(import this)

That day was last week! [python] index of absolute maximum value in a list you are making progress through persistence!
More on lambdas here:
https://dbader.org/blog/python-lambda-functions

1 Like

Indeed. Actually recently I was looking at scripts I created a year ago and I found numerous ways to make them work better with less code. :slight_smile:

1 Like