0

This question only uses a single index for each element. I am trying to do the same but with repetitions in the list, so the values in the dict will be lists of indexes.

I have the following code that reduces a list to a dict:

def list_to_dict(l):
    d = {}
    for i in range(len(l)):
        if l[i] not in d:
            d[l[i]] = []
        d[l[i]].append(i)

    return d

print(list_to_dict([1, 2, 3, 1]))
# Gives: {1: [0, 3], 2: [1], 3: [2]}

May I know if there is a more pythonic/efficient way to do this?

Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
Kallzvx
  • 594
  • 7
  • 23
  • 3
    [`defaulltdict(list)`](https://docs.python.org/3/library/collections.html#collections.defaultdict)? – Ch3steR Dec 02 '21 at 12:41
  • @Tomerikoo I was looking for a one-liner, but it seems like this is the best we can get. Not sure if this count as duplicate. – Kallzvx Dec 02 '21 at 14:09
  • Almost anything can be one line, but it doesn't mean it's better... This can be done in an ugly, inefficient one-liner: `{x: [i for i, val in enumerate(l) if val == x] for x in set(l)}` – Tomerikoo Dec 02 '21 at 14:12
  • ^ `O(N^2)` instead of the `O(N)` in the answers below... – Tomerikoo Dec 02 '21 at 14:20

2 Answers2

1

It looks like you're trying to construct a Tree as an Adjacency list, given that arr[i] represents the parent of the node i. If arr is given to you, you can use the following way to construct the adjacency list.

from collections import defaultdict

def reduce_list_to_map(arr):
    adj = defaultdict(list)
    for i in range(len(arr)):
        adj[arr[i]].append(i)
    return adj
-1

You can just use the dict method setdefault instead of checking if the key exists. Also, instead of looping over indexes, it is cleaner to use enumerate:

def list_to_dict(l):
    d = {}
    for i, val in enumerate(l):
        d.setdefault(val, []).append(i)

    return d

print(list_to_dict([1, 2, 3, 1]))
# Gives: {1: [0, 3], 2: [1], 3: [2]}
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61