[Tutor] Find Elements in List That Equal A Specific Value

Steven D'Aprano steve at pearwood.info
Thu May 13 02:20:01 CEST 2010


On Thu, 13 May 2010 03:58:45 am Su Chu wrote:

> My problem is as follows:
> I have three lists, one with unique values (list 1), one a sequence
> of values that are not necessarily unique (list2), and a shorter list
> with the unique values of list 2 (list 3). List 1 and List 2 are of
> equal lengths.
>
>
> An example:
> list1 = [ 1, 2, 3, 4, 5, 6 ]
> list2 = [ 2, 2, 2, 5, 6, 6 ]
> list3 = [2, 5, 6]
>
> What I would like to do is find and sum the elements of list 1 given
> its corresponding element in list 2 is equal to some element in list
> 3.

Rather than trying to find a single magic command that happens to do 
exactly what you want, let's break that up into individual steps and 
walk through it by hand.

Start at the end -- you want to match elements from list2 which equals a 
particular value. Where that value comes from doesn't matter.

results = []
for el in list2:
    if el = value:
        results.append(el)


Unfortunately, doing this loses the information we really need: the 
*position* of the element. We don't actually care about the element 
itself. How can we get the position? That's what the enumerate() 
function is for, it takes a list and lazily returns pairs of (position, 
element). So let's adapt the for-loop to do the job:

positions = []
for (pos, el) in enumerate(list2):
    if el == value:
        positions.append(pos)


This can be written as a "list comprehension", which is syntactic sugar 
for a loop:

positions = [pos for (pos, el) in enumerate(list2) if el == value]


Now we have a list of positions. We need to extract the elements in 
list1 at those positions. Here's a for-loop to do it:

elements = []
for pos in positions:  # positions defined above
    elements.append(list1[pos])


And as list comps:

positions = [pos for (pos, el) in enumerate(list2) if el == value]
elements = [list1[pos] for pos in positions]


But we don't need two separate loops, we can combine them into one loop:

elements = []
for (pos, el) in enumerate(list2):
    if el == value:
        elements.append(list1[pos])

And as a single list comp:

elements = [list1[pos] for (pos,el) in enumerate(list2) if el in list3]

And now sum them:

sum(elements)


Now let's put this into a function, so you can call it with different 
values:


def extract_and_sum(list1, list2, value):
    elements = [list1[i] for (i,x) in enumerate(list2) if x in list3]
    return sum(elements)


And now call it in a loop:


sums = []
for value in list3:
    sums.append(extract_and_sum(list1, list2, value))


And you are done.



-- 
Steven D'Aprano


More information about the Tutor mailing list