Convert an array of integers to an index dictionary

I have a (large) integer array like

materials = [0, 0, 47, 0, 2, 2, 47]  # ...

with several unique elements, and I would like to convert it to a dictionary of indices, i.e.

d = {
    0: [0, 1, 3],
    2: [4, 5],
    47: [2, 6],
    }

What is the most effective way to do this? (NumPy is welcome.)

+4
source share
8 answers

Another one line, this time with numpy.where:

out = {v: np.where(v == a)[0] for v in numpy.unique(a)}

(For some applications, a logical array is sufficient:

out = {v: v == a for v in numpy.unique(a)}

)

Please note that it is numpy.uniquefaster than set()for large arrays, and a large margin if there are only a few unique entries.

Anyway, for most array sizes, this is the fastest way:

10 different integers: enter image description here

100 : enter image description here

:

import numpy as np
from collections import defaultdict
import perfplot


def pp(a):
    index = np.argsort(a, kind='mergesort')
    as_ = a[index]
    jumps = np.r_[0, 1 + np.where(np.diff(as_) != 0)[0]]
    pp_out = {k: v for k, v in zip(as_[jumps], np.split(index, jumps[1:]))}
    return pp_out


def pp2(a):
    index = np.argsort(a)
    as_ = a[index]
    jumps = np.r_[0, 1 + np.where(np.diff(as_) != 0)[0]]
    pp_out = {k: np.sort(v)
              for k, v in zip(as_[jumps], np.split(index, jumps[1:]))}
    return pp_out


def Denziloe_JFFabre(a):
    df_out = {v: [i for i, x in enumerate(a) if x == v] for v in np.unique(a)}
    return df_out


def FCouzo(a):
    fc_out = defaultdict(list)
    for i, elem in enumerate(a):
        fc_out[elem].append(i)
    return fc_out


def KKSingh(a):
    kks_out = defaultdict(list)
    list(map(lambda x: kks_out[x[0]].append(x[1]), zip(a, range(len(a)))))
    return kks_out


def TMcDonaldJensen(a):
    mdj_out = defaultdict(list)
    for i, elem in enumerate(a):
        mdj_out[elem].append(i)
    return mdj_out


def RomanPerekhrest(a):
    rp_out = {}
    for k, m in enumerate(a):
        rp_out.setdefault(m, []).append(k)
    return rp_out


def SchloemerHist(a):
    np.histogram(a, bins=np.arange(min(a), max(a)+2))
    return


def SchloemerWhere(a):
    out = {v: np.where(v == a)[0] for v in np.unique(a)}
    return out


def SchloemerBooleanOnly(a):
    out = {v: v == a for v in np.unique(a)}
    return out


perfplot.show(
        setup=lambda n: np.random.randint(0, 100, n),
        kernels=[
            pp, pp2, Denziloe_JFFabre, FCouzo, KKSingh,
            TMcDonaldJensen, RomanPerekhrest, SchloemerHist, SchloemerWhere,
            SchloemerBooleanOnly
            ],
        n_range=[2**k for k in range(17)],
        xlabel='len(a)',
        logx=True,
        logy=True,
        )
+1

enumerate() dict.setdefault():

materials = [0, 0, 47, 0, 2, 2, 47]
d = {}
for k,m in enumerate(materials):
    d.setdefault(m, []).append(k)

print(d)

:

{0: [0, 1, 3], 2: [4, 5], 47: [2, 6]}
+4

numpy, python, dict :

materials = [0, 0, 47, 0, 2, 2, 47]

d = {v : [i for i,x in enumerate(materials) if x==v] for v in set(materials)}

print(d)

:

{0: [0, 1, 3], 2: [4, 5], 47: [2, 6]}

[i for i,x in enumerate(materials) if x==v] (index )

, , , , n, .

, - , , set!

+3

collections.defaultdict , , .

from collections import defaultdict

indices = defaultdict(list)

for i, elem in enumerate(materials):
    indices[elem].append(i)
+3

:

import numpy as np

a = np.random.randint(0, 1000, 1000000)
index = np.argsort(a, kind='mergesort')
as_  = a[index]
jumps = np.r_[0, 1 + np.where(np.diff(as_) != 0)[0]]
result = {k: v for k, v in zip(as_[jumps], np.split(index, jumps[1:]))}

numpy n; O (n log n), slim (pp2 - , , quicksort , pp3 argpartition , .):

10 : enter image description here

100 : enter image description here

:

import numpy as np
from collections import defaultdict
import perfplot


def pp(a):
    index = np.argsort(a, kind='mergesort')
    as_ = a[index]
    jumps = np.r_[0, 1 + np.where(np.diff(as_) != 0)[0]]
    pp_out = {k: v for k, v in zip(as_[jumps], np.split(index, jumps[1:]))}
    return pp_out


def pp2(a):
    index = np.argsort(a)
    as_ = a[index]
    jumps = np.r_[0, 1 + np.where(np.diff(as_) != 0)[0]]
    pp_out = {k: np.sort(v)
              for k, v in zip(as_[jumps], np.split(index, jumps[1:]))}
    return pp_out


def Denziloe_JFFabre(a):
    df_out = {v: [i for i, x in enumerate(a) if x == v] for v in set(a)}
    return df_out


def FCouzo(a):
    fc_out = defaultdict(list)
    for i, elem in enumerate(a):
        fc_out[elem].append(i)
    return fc_out


def KKSingh(a):
    kks_out = defaultdict(list)
    list(map(lambda x: kks_out[x[0]].append(x[1]), zip(a, range(len(a)))))
    return kks_out


def TMcDonaldJensen(a):
    mdj_out = defaultdict(list)
    for i, elem in enumerate(a):
        mdj_out[elem].append(i)
    return mdj_out


def RomanPerekhrest(a):
    rp_out = {}
    for k, m in enumerate(a):
        rp_out.setdefault(m, []).append(k)
    return rp_out


def SchloemerHist(a):
    np.histogram(a, bins=np.arange(min(a), max(a)+2))
    return


def SchloemerWhere(a):
    out = {v: np.where(v == a)[0] for v in set(a)}
    return out


perfplot.show(
        setup=lambda n: np.random.randint(0, 10, n),
        kernels=[
            pp, pp2, Denziloe_JFFabre, FCouzo, KKSingh,
            TMcDonaldJensen, RomanPerekhrest, SchloemerHist, SchloemerWhere
            ],
        n_range=[2**k for k in range(19)],
        xlabel='len(a)',
        logx=True,
        logy=True,
        )
+3
source

Understanding can make it beautiful:

d = {key:[i for i, v in enumerate(materials) if v == key] for key in set(materials)}
+1
source

I would use defaultdictthis more efficiently ( O(n)time compared to Jean's answer, which O(n^2)):

from collections import defaultdict
materials = [0, 0, 47, 0, 2, 2, 47]
d = defaultdict(list)
for i, elem in enumerate(materials):
    d[elem].append(i)

d now equal to:

defaultdict(<type 'list'>, {0: [0, 1, 3], 2: [4, 5], 47: [2, 6]})
+1
source

For the pleasure of this, here is a solution using numpy.histogram:

np.histogram(a, bins=np.arange(min(a), max(a)+2))

I thought it would be good, but Paul's solution is still better:

enter image description here

0
source

Source: https://habr.com/ru/post/1672072/


All Articles