[Python] List processing algorithm out of ideas

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

I’ve been looking through my old scripts as well!

https://imgs.xkcd.com/comics/code_quality_3.png

1 Like