0

I have a particular problem that has me stumped. Suppose I have the following two lists:

x = ["A","B","C","D","E"]
y = [1,2,3,2,1]

x and y have a relationship. The relationship is tied by index. That is, "A" relates to 1, "B" related to 2, "C" related to 3 and so on.

What I am trying to do is create a key value relation where the unique items in y are keys and each key has a list that contains the letters related to the key as mentioned previously. I attempted to do the following:

mapping = dict(zip(y,x))
{1: 'E', 2: 'D', 3: 'C'}

This overwrites the previous letter. I would love to be able to return the following:

{1:['A','E'], 2:['B','D'], 3:['C']}

Anyone have a clever solution to this? Preferably without itertools.

theamateurdataanalyst
  • 2,794
  • 4
  • 38
  • 72

4 Answers4

6

You can use setdefault

x = ["A","B","C","D","E"]
y = [1,2,3,2,1]
d = {}
for i,j in zip(y,x):
    d.setdefault(i, []).append(j)
print d

Output:

{1: ['A', 'E'], 2: ['B', 'D'], 3: ['C']}
Joe T. Boka
  • 6,554
  • 6
  • 29
  • 48
2

A defaultdict is my preference for situations like this.

from collections import defaultdict

x = ["A","B","C","D","E"]
y = [1,2,3,2,1]
D = defaultdict(list)

for i, j in zip(x, y):
    D[j].append(i)

print dict(D)

Output is:

{1: ['A', 'E'], 2: ['B', 'D'], 3: ['C']}
therealrootuser
  • 10,215
  • 7
  • 31
  • 46
  • 1
    I have no comment on the accuracy of your answer, or on how useful such an answer is when a duplicate question was linked before this question had any answers. I'm simply trying to calm you down and explain the fact that sometimes you will be downvoted and sometimes the downvoter will not leave a comment. Take a deep breath and relax; it's no biggie. :) – TigerhawkT3 Aug 21 '15 at 04:17
1

Here is a clever, but O(n^2) and therefore not advised solution that I came up with using a combination of Python's dictionary & list comprehension.

>>> x = ["A","B","C","D","E"]
>>> y = [1,2,3,2,1]
>>> {y[i] : [x[j] for j in range(len(y)) if y[j] == y[i]] for i in range(len(y))}
{1: ['A', 'E'], 2: ['B', 'D'], 3: ['C']}

For what its worth, @Joe R and @mattingly890 solutions are the way to go, since they are O(n) solutions

nmio
  • 778
  • 5
  • 19
0

Here is a simple (not clever) solution. I would argue that a simple solution is more in keeping with pythons philosophy than a clever solution. Perl is a language that's designed to maximise cleverness, imho, and I find it nigh on unreadable (admittedly I avoid it if I can so am an inexperienced Perl programmer).

x = ["A","B","C","D","E"]
y = [1,2,3,2,1]

assert(len(x) == len(y))

d = {}
for i in range(len(x)):
    key = y[i]
    val = x[i]

    if key in d:
       d[key].append(val)
    else: 
       d[key] = [val, ]

print d
demented hedgehog
  • 7,007
  • 4
  • 42
  • 49
  • Philosophically this isn't purely a Pythonic solution either. See https://docs.python.org/2/glossary.html#term-eafp – therealrootuser Aug 21 '15 at 03:38
  • An `if..else` like this is just fine. – TigerhawkT3 Aug 21 '15 at 03:50
  • @mattingly890 Maybe, but you know you're going to get invalid keys here.. so the assumption that you're not seems a little broken. It is, for example, perfectly reasonable for every loop to generate an exception in this case. I get the argument though. E.g. see here http://stackoverflow.com/questions/180937/are-exceptions-really-for-exceptional-errors and http://stackoverflow.com/questions/3086806/python-exceptions-eafp-and-what-is-really-exceptional this code as it stands suggests that missing keys are a normal occurrence. – demented hedgehog Aug 21 '15 at 03:51