0

Let's say currently i have a list with:

L = [[1,'JAYCE'],[2,'AMIE'],[3,'JACK'],[4,'STEVE'],[5,'JAYCE']]

and i have another list which contains the names sorted in order:

sortedNames = ['AMIE','JACK','JAYCE','JAYCE','STEVE']

The output I want to get is, based on the sorted names list, i want to add the ID back to the names in the sorted order which is based off the sortedNames list.

finalist = [[2,'AMIE'],[3,'JACK'],[1,'JAYCE'],[5,'JAYCE'],[4,'STEVE']]

Note that Jayce appeared twice so even if the first occurrence of Jayce has 5, followed by 1, its totally fine too.

I've been thinking of something like:

L = [[1,'JAYCE'],[2,'AMIE'],[3,'JACK'],[4,'STEVE'],[5,'JAYCE']]
sortedNames = ['AMIE','JACK','JAYCE','JAYCE','STEVE']

finalist = []
for i in sortedNames:
    j = 0
    if i in L[j][1]:
        finalist.append(L[0] + i)
    j+=1

print(finalist)

I'm getting an error saying:

TypeError: can only concatenate list (not "str") to list

I'm definitely appending it wrong.

Uyghur Lives Matter
  • 18,820
  • 42
  • 108
  • 144
clink
  • 213
  • 3
  • 11
  • Can you just sort `L` on the names? – wwii Mar 17 '18 at 02:34
  • `sorted` take a key argument `sorted([[1,'JAYCE'],[2,'AMIE'],[3,'JACK'],[4,'STEVE'],[5,'JAYCE']], key=lambda x: x[1])` – f5r5e5d Mar 17 '18 at 02:34
  • @f5r5e5d, why not sort the list in place with its own method? – wwii Mar 17 '18 at 02:35
  • `L.sort(key=lambda x: x[1])` works too. the `.append()` can be fixed by wrapping `i` in a list: `finalist.append(L[0] + [i])` – f5r5e5d Mar 17 '18 at 02:39
  • 1
    And another.. [How to sort a list according to another list](https://stackoverflow.com/q/12814667/2823755) – wwii Mar 17 '18 at 02:43

3 Answers3

1

So, as long as your data is well behaved, you could group your numbers into deques using a defaultdict:

In [14]: from collections import defaultdict, deque

In [15]: grouper = defaultdict(deque)

In [16]: for a,b in L:
    ...:     grouper[b].append(a)
    ...:

Then simply:

In [17]: grouper
Out[17]:
defaultdict(collections.deque,
            {'AMIE': deque([2]),
             'JACK': deque([3]),
             'JAYCE': deque([1, 5]),
             'STEVE': deque([4])})

In [18]: [[grouper[x].popleft(), x] for x in sortedNames]
Out[18]: [[2, 'AMIE'], [3, 'JACK'], [1, 'JAYCE'], [5, 'JAYCE'], [4, 'STEVE']]

I realize it is an ugly wart to use pop inside a list comprehension...

Here's an approach using only dict and list:

In [19]: grouper = {}
    ...: for a,b in L:
    ...:     grouper.setdefault(b, []).append(a)
    ...:

In [20]: grouper = {k:v[::-1] for k, v in grouper.items()}

In [21]: [[grouper[x].pop(), x] for x in sortedNames]
Out[21]: [[2, 'AMIE'], [3, 'JACK'], [1, 'JAYCE'], [5, 'JAYCE'], [4, 'STEVE']]

Both approaches are O(N).

Edit

I just realized that what you really want is instead of generating a list of sorted names, just sort L using a key directly:
In [26]: L
Out[26]: [[1, 'JAYCE'], [2, 'AMIE'], [3, 'JACK'], [4, 'STEVE'], [5, 'JAYCE']]

In [27]: from operator import itemgetter

In [28]: sorted(L, key=itemgetter(1))
Out[28]: [[2, 'AMIE'], [3, 'JACK'], [1, 'JAYCE'], [5, 'JAYCE'], [4, 'STEVE']]
juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
1

You can use the sorted() function to do this, and lookup the position of the stored name using its key argument:

finalList = sorted(L, key=lambda x: sortedNames.index(x[1]))

Which results in:

[[2, 'AMIE'], [3, 'JACK'], [1, 'JAYCE'], [5, 'JAYCE'], [4, 'STEVE']]
Uyghur Lives Matter
  • 18,820
  • 42
  • 108
  • 144
0

You can create a dictionary by grouping each name to a listing of all the IDs found for the name. Then, next can be applied.

import itertools
L = [[1,'JAYCE'],[2,'AMIE'],[3,'JACK'],[4,'STEVE'],[5,'JAYCE']]
new_l = {a:iter([c for c, _ in b]) for a, b in itertools.groupby(sorted(L, key=lambda x:x[-1]), key=lambda x:x[-1])}
sortedNames = ['AMIE','JACK','JAYCE','JAYCE','STEVE']
final_data = [[next(new_l[i]), i] for i in sortedNames]

Output:

[[2, 'AMIE'], [3, 'JACK'], [1, 'JAYCE'], [5, 'JAYCE'], [4, 'STEVE']]

Edit:

It is also possible to utilize sorted:

L = [[1,'JAYCE'],[2,'AMIE'],[3,'JACK'],[4,'STEVE'],[5,'JAYCE']]
sortedNames = ['AMIE','JACK','JAYCE','JAYCE','STEVE']
new_result = sorted(L, key=lambda x:(sortedNames.index(x[-1]), x[0]))

Output:

[[2, 'AMIE'], [3, 'JACK'], [1, 'JAYCE'], [5, 'JAYCE'], [4, 'STEVE']]
Ajax1234
  • 69,937
  • 8
  • 61
  • 102