Home > Software design >  Filter a dictionary of lists
Filter a dictionary of lists

Time:02-20

I have a dictionary of the form: {"level":[1,2,3], "conf":[-1,1,2], "text":["here","hel","llo"]}

I want to filter the lists to remove every item at index i, where "conf" at index i is not >0.
So for example if I have an input like this:
{"level":[1,2,3], "conf":[-1,1,2], "text":["here","hel","llo"]}

The output should be this:

{"level":[2,3], "conf":[1,2],text:["hel","llo"]}

as the first value of conf was not > 0.

I have tried something like this:

new_dict = {i: [a for a in j if a >= min_conf] for i, j in my_dict.items()}

But that would work just for one key.

REPLY: Lot of good solutions below. I just thought about another one.

  • Turn this dict of list structure into a list of tuple: tuples =[(1,-1,"here"), (2, 1, "hel"),(3,"2","llo")]
  • then I just have to filter this list by the 2nd item of each tuple which is quite easy: filter(lambda item: item[1] >= 0, tuples)

CodePudding user response:

I would keep the indexes of valid elements (those greater than 0) with:

kept_keys = [i for i in range(len(my_dict['conf'])) if my_dict['conf'][i] > 0]

And then you can filter each list checking if the index of a certain element in the list is contained in kept_keys:

{k: list(map(lambda x: x[1], filter(lambda x: x[0] in kept_keys, enumerate(my_dict[k])))) for k in my_dict}

Output:

{'level': [2, 3], 'conf': [1, 2], 'text': ['hel', 'llo']}

CodePudding user response:

try:

from operator import itemgetter


def filter_dictionary(d):
    conf = d['conf']
    positive_indices = [i for i, item in enumerate(conf) if item > 0]
    f = itemgetter(*positive_indices)
    return {k: list(f(v)) for k, v in d.items()}


d = {"level": [1, 2, 3], "conf": [-1, 1, 2], "text": ["-1", "hel", "llo"]}
print(filter_dictionary(d))

output:

{'level': [2, 3], 'conf': [1, 2], 'text': ['hel', 'llo']}

I tried to first see which indices of 'conf' are positive, then with itemgetter I picked those indices from values inside the dictionary.

CodePudding user response:

I solved it with this:

from typing import Dict, List, Any, Set

d = {"level":[1,2,3], "conf":[-1,1,2], "text":["-1","hel","llo"]}

filtered_indexes = set([i for i in range(len(d.get('conf', []))) if d.get('conf')[i] > 0])

def filter_dictionary(d: Dict[str, List[Any]], filtered_indexes: Set[int]) -> Dict[str, List[Any]]:
    for key, list_values in d.items():
        d[key] = [value for i, value in enumerate(list_values) if i in filtered_indexes]
    return d

print(filter_dictionary(d, filtered_indexes))

Output:

{'level': [2, 3], 'conf': [1, 2], 'text': ['hel', 'llo']}

CodePudding user response:

a = {"level":[1,2,3], "conf":[-1,1,2],"text":["-1","hel","llo"]}

for k, v in a.items():
    if k == "conf":
        for element in v:
            if element < 0:
                to_delete = [] #it will store the index numbers of the conf that you want to delete(conf<0)
                to_delete.append(v.index(element))

for position in to_delete:
    for k, v in a.items():
        v.pop(position)

and then a will be {'level': [2, 3], 'conf': [1, 2], 'text': ['hel', 'llo']} which is what you want.

CodePudding user response:

You can have a function which works out which indexes to keep and reformulate each list with only those indexes:

my_dict = {"level":[1,2,3], "conf":[-1,1,2],'text':["-1","hel","llo"]}

def remove_corresponding_items(d, key):
    keep_indexes = [idx for idx, value in enumerate(d[key]) if value>0]
    for key, lst in d.items():
        d[key] = [lst[idx] for idx in keep_indexes]

remove_corresponding_items(my_dict, 'conf')
print(my_dict)

Output as requested

CodePudding user response:

Lots of good answers. Here's another 2-pass approach:

mydict = {"level": [1, 2, 3], "conf": [-1, 1, 2], 'text': ["-1", "hel", "llo"]}

for i, v in enumerate(mydict['conf']):
    if v <= 0:
        for key in mydict.keys():
            mydict[key][i] = None

for key in mydict.keys():
    mydict[key] = [v for v in mydict[key] if v]

print(mydict)

Output:

{'level': [2, 3], 'conf': [1, 2], 'text': ['hel', 'llo']}

CodePudding user response:

I believe this will work:

d = {"level":[1,2,3], "conf":[-1,1,2], "text":["-1","hel","llo"]}
for key in d:
    if key != "conf":
        d[key] = [d[key][i] for i in range(len(d[key])) if d["conf"][i] >= 0]
d["conf"] = [i for i in d["conf"] if i>=0]
print(d)

Output: {'level': [2, 3], 'conf': [1, 2], 'text': ['hel', 'llo']}

CodePudding user response:

Try this:

a_dict = {"level": [1, 2, 3], "conf": [-1, 1, 2], "text": ["-1", "hel", "llo"]}
for a_list in a_dict.values():
    print(a_list)
    iterations = 0
    for item in a_list[::-1]:
        if iterations >= 2:
            a_list.remove(item)
        iterations  = 1   
print(a_dict)

Output:

{'level': [2, 3], 'conf': [1, 2], 'text': ['hel', 'llo']}
  • Related