Python scripting help


#1

This is more a python question than a Rhino question, as I am still learning python. So I have a list and I wanted to find the indexes for each item if they occur more than once. The answer I found on Stackover flow was the following:

Fruit = [‘apple’,‘pear’,‘peach’,‘pear’]
index = [i for i, x in enumerate(Fruit) if x == “pear”]
print(index)

result = [1, 3]

Since this seem extremely condensed, I was wondering if anyone would be willing describe what is happening in lamen terms. I understand what the enumerate() function does where is returns the index and the value of given list, just not sure what the i for i is doing.

Thanks for the help in advance.


(Nathan 'jesterKing' Letwory) #2

[i for i, x in enumerate(Fruit) if x == "pear"]
This is a list comprehension. The first part to focus on is the enumerate call. This essentially will yield a tuple for each list item. The tuple consists of an index, and the item itself. This tuple is ‘unpacked’ directly by the i, x bit. Now if you ignore the for i, x in enumerate(Fruit) bit you’ll see it reads i if x == "pear". So essentially we’re saying use i if x equals “pear”. This is done for each item in the list. The index is given and the item. The item is checked for equality, and the index is saved if x equals “pear”.


(Nathan 'jesterKing' Letwory) #3

Once you get the hang of list comprehensions (and along the same lines dictionary comprehensions) they are a powerful way of expression in one line what otherwise would go over one or more nested for loops.

Mind you, it is easy to go overboard and create intricate list comprehensions that are hard to follow.

Also, list comprehensions aren’t necessarily the best solution for performance.

But they can make code read easily and keep it succinct.


#4

Thanks that helps a lot. I will have to chew on it a bit to make sure I understand whats going on, but I am sure a lot closer .


#5

For that you would use a defaultdict:

from collections import defaultdict

fruits = ['apple', 'apple', 'pear', 'strawberry', 'peach', 'pear', 'plane', 'ship', 'strawberry', 'strawberry']

d = defaultdict(list)
for i, fruit in enumerate(fruits):
    d[fruit].append(i)

for fruit, indices in d.items():
    if len(indices) > 1:
        print fruit, indices

#6

I haven’t used enumerate() but by looking at it I think it returns a list of tuples, each of which has the index as first element and list item as the second. so enumerate() itself above yields [(0,‘apple’), (1,‘pear’), (2,‘peach’), (3,‘pear’)]. then ‘for i,x in enumerate()’ will iterate through this list with tuple unpacking. ‘i’ will be 0,1,2… and ‘x’ is ‘apple’, ‘pear’,…

if you unfold the list comprehension it’s this:(I’m using …as indent)
index = []
for i,x in enumerate(Fruit):
… if x==‘pear’:
… index.append(i)


#7

Thanks. That it what I was looking for. I am starting to get a better handle on list comprehension.


#8

Kind of a slightly different example, but I think i am getting it. Correct me if I am wrong, and again thanks for the help.

The example below could be written like this?

Fruit = [('apple',2),('pear',6),('peach',4),('pear',8)] Value = [x for i, x in Fruit if i == 'pear'] print(Value) Value = [] for **i, x** in Fruit: .....if i == 'pear': ..........Value.append(x)

One thing that I didn’t realize is that you can declare variables for each value in a tuple in the for statment, the i,x part. Prior to this I would have written it like this.

Value = [] for x in Fruit: .....if x[0] == 'pear': ..........Value.append(x[1])