2

I have some dictionary

someDict = {
    'foo1': [1, 4, 7, 0, -2],
    'foo2': [0, 2, 5, 3, 6],
    'foo3': [1, 2, 3, 4, 5]
}

I would like to loop over all the elements in each list with Python 3, and when the element at some given index equals zero, I want to delete that element at that index for all the lists/properties in the dictionary. So that the dictionary ends up as

someDict = {
    'foo1': [4, 7, -2],
    'foo2': [2, 5, 6],
    'foo3': [2, 3, 5]
}

Please note that I don't know beforehand how many keys/lists the dictionary will have, and I don't know how many elements the list will contain. I have come up with the following code, which seems to work, but was wondering if there is a more efficient way to do this?

keyPropList = someDict.items()
totalList = []

for tupleElement in keyPropList:
    totalList.append(tupleElement[1])

copyTotalList = totalList[:]
for outerRow in copyTotalList:
    for outerIndex, outerElement in enumerate(outerRow):
        if outerElement==0:
            for innerIndex, _ in enumerate(copyTotalList):
                del totalList[innerIndex][outerIndex]

print('someDict =', someDict)
Hunter
  • 357
  • 8
  • 15
  • What should happen if `'foo1': [0, 4, 7, 1, -2]` and `'foo2': [2, 0, 5, 3, 6]` Should deleting the first element of foo2 happen first? – Mark Dec 11 '18 at 20:00
  • @MarkMeyer, I would want to end with `'foo1': [7, 1, -2]` and `'foo2': [5, 3, 6]` if that makes sense – Hunter Dec 11 '18 at 20:02

3 Answers3

8

You can find a list of "banned" indices which can then be used to filter the structure:

someDict = {
  'foo1': [1, 4, 7, 0, -2],
  'foo2': [0, 2, 5, 3, 6],
  'foo3': [1, 2, 3, 4, 5]
}
results = {i for c in someDict.values() for i, a in enumerate(c) if not a}
new_dict = {a:[c for i, c in enumerate(b) if i not in results] for a, b in someDict.items()}

Output:

{'foo1': [4, 7, -2], 'foo2': [2, 5, 6], 'foo3': [2, 3, 5]}
Ajax1234
  • 69,937
  • 8
  • 61
  • 102
3

Here's a cheeky one-liner:

>>> dict(zip(someDict, map(list, zip(*(ts for ts in zip(*someDict.values()) if all(ts))))))
{'foo3': [2, 3, 5], 'foo1': [4, 7, -2], 'foo2': [2, 5, 6]}
>>>
juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
0

Other option, more verbose and destructive (pop) for original_dict:

some_dict = {
    'foo1': [1, 0, 2, 3, -2],
    'foo2': [0, 2, 5, 3, 6],
    'foo3': [1, 2, 3, 0, 5]
}

for k, v in some_dict.items():
  id = []
  for i, e in enumerate(v):
    if e == 0: id.append(i-len(id))
  [ [ some_dict[k].pop(x) for x in id ] for k,v in some_dict.items() ]

print(some_dict)
#=> {'foo1': [2, -2], 'foo2': [5, 6], 'foo3': [3, 5]}
iGian
  • 11,023
  • 3
  • 21
  • 36
  • do *not* use `.pop` inside a list comprehension. [List comprehensions should be free of side-effects](https://stackoverflow.com/questions/5753597/is-it-pythonic-to-use-list-comprehensions-for-just-side-effects). Just use a loop if you are going to use methods with side-effects. – juanpa.arrivillaga Dec 13 '18 at 21:52