14

I have the following code:

list1 = [('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400), ('f', 500)]
list2 = [[0, 200, 400], [100, 300, 500]]

list2 just basically reorganizes the numbers into teams, the 2 sublists.

My list3 would then be:

list3 = [['a', 'c', 'e'], ['b', 'd', 'f']]

So by looking up the values in list2 in list1, what code do I need to produce list3?

This is also valid:

list1 = [('a', 0), ('b', 0), ('c', 0), ('d', 0), ('e', 0), ('f', 0)]
list2 = [[0, 0, 0], [0, 0, 0]]

It would give:

list3 = [['a', 'b', 'c'], ['d', 'e', 'f']]

So basically 'a' and 'f' could have the same value but they can only return once in list3

6
  • I would try to come up with a more succinct way of asking the question.. Commented May 8, 2020 at 19:11
  • 1
    @MikeQ What's not succinct about it? It seems fine to me. Commented May 8, 2020 at 19:12
  • Can you post your code for creating list2 from list1? It should follow the same logic, or the question is not clear Commented May 8, 2020 at 19:12
  • @Sri list2 is not created from list1. I'm not sure what you're confused about though. Commented May 8, 2020 at 19:13
  • @wjandrea I like it a lot more now, too much ancillary info before. Commented May 8, 2020 at 20:26

7 Answers 7

8

A possibility is to use collections.defaultdict with collections.deque:

from collections import defaultdict, deque
def to_num(a, b):
  d = defaultdict(deque)
  for j, k in a:
     d[k].append(j)
  return [[d[l].popleft() for l in i] for i in b]

list1 = [('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400), ('f', 500)]
list2 = [[0, 200, 400], [100, 300, 500]]
print(to_num(list1, list2))

Output:

[['a', 'c', 'e'], ['b', 'd', 'f']]

With your second test case:

list1 = [('a', 0), ('b', 0), ('c', 0), ('d', 0), ('e', 0), ('f', 0)]
list2 = [[0, 0, 0], [0, 0, 0]]
print(to_num(list1, list2))

Output:

[['a', 'b', 'c'], ['d', 'e', 'f']]
Sign up to request clarification or add additional context in comments.

2 Comments

Why do you use a deque instead of a list? Is it because deque.popleft() is faster than list.pop(0)?
@wjandrea deque.popleft() is indeed faster than list.pop(0), see here. Additionally, I think that a "remove from the front" operation best fits the deque paradigm.
4

You can first collect first values of elements of list1 depending on second element of values of list1:

from collections import deque, defaultdict
byvalue = defaultdict(deque)
for name, value in list1:
    byvalue[value].append(name)

then you can collect back the result by processing list2

list3 = [[byvalue[value].popleft() for value in x]
         for x in list2]

Comments

3

Here's an idea using pop to avoid duplicate items:

def pop_element(inp_list, search_value): 
    for index, (_, query_value) in enumerate(inp_list): 
        if query_value == search_value: 
            return inp_list.pop(index)[0] 

list1 = [('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400), ('f', 500)]
list2 = [[0, 200, 400], [100, 300, 500]]
list3 = [[pop_element(list1, value) for value in inner_list] for inner_list in list2]

# list 3 is [['a', 'c', 'e'], ['b', 'd', 'f']]

It also works on your other example:

list1 = [('a', 0), ('b', 0), ('c', 0), ('d', 0), ('e', 0), ('f', 0)]   
list2 = [[0, 0, 0], [0, 0, 0]]                                                                                                                                
list3 = [[pop_element(list1, value) for value in inner_list] for inner_list in list2]

# list3 is [['a', 'b', 'c'], ['d', 'e', 'f']]

And it conveniently places None values when a value from list2 is not found:

list1 = [('a', 0), ('b', 0), ('c', 0), ('d', 0), ('e', 0), ('f', 0)]   
list2 = [[0, 0, 11], [0, 'this is a value', 0]]                                                                                                                                
list3 = [[pop_element(list1, value) for value in inner_list] for inner_list in list2]

# list3 is [['a', 'b', None], ['c', None, 'd']]

The only caveat is that this method turns list1 into an empty list, so you might want to do list1_copy = list1.copy() and pass that to the list comprehension instead.

Comments

1

Using lamdba function and generator

def find(x):
    " find matching value of x in lst2 " 
    return next(t[0] for t in list1 if t[1]==x)

list3 = [[find(a) for a in sublist] for sublist in list2]

print(list3)
# out: [['a', 'c', 'e'], ['b', 'd', 'f']]

2 Comments

Named lambdas are bad practice. Use a def instead.
@wjandrea--agreed, and understand from PEP 8 but like the brevity here.
1

Like this:

In [220]: list3 = []

In [221]: dict1 = dict(list1)

In [225]: for i in list2:
     ...:     l = [] 
     ...:     for j in i: 
     ...:         l.append(list(dict1.keys())[list(dict1.values()).index(j)]) 
     ...:     list3.append(l) 
     ...:     

In [226]: list3
Out[226]: [['a', 'c', 'e'], ['b', 'd', 'f']]

Comments

0
list1 = [('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400), ('f', 500)]

list2 = [[0, 200, 400], [100, 300, 500]]
list3 = []

#Loop through each sublist in list 2
for sublist in list2:
    #creating an inner list which will go in list3
    inner = []
    for el in sublist:
        for (index, (title, label)) in enumerate(list1):
            if label == el:
                inner.append(title)
                #remove the first element that matches the current label
                list1.pop(index)
                break

    list3.append(inner)

print(list3)

Output

[['a', 'c', 'e'], ['b', 'd', 'f']]

Comments

0

The easiest way is using collections.OrderedDict

code:

list1 = [('a', 0), ('b', 100), ('c', 200), ('d', 300), ('e', 400), ('f', 500)]
list2 = [[0, 200, 400], [100, 300, 500]]
list4 = list2[:]
l1_as_dict = OrderedDict(list1)
for key,value in l1_as_dict.items():

    #spread out list,find the first position,then break double-loop
    for i,a_item in enumerate(list2):
        for j,item in enumerate(list2[i]):
            if value == item:
                list4[i][j] = key
                break
        else:
            continue
        break
print(list4)

output:

[['a', 'c', 'e'], ['b', 'd', 'f']]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.