Question

I have an OrderedDict with elements (as in carbon and iron) ordered like the periodic table. I need to pull out some elements in an arbitrary order and retain the arbitrary order so they match up for later math using numpy.

If I do a list comprehension on the OrderedDict, I get the elements in the OrderedDict order. But if I convert it to a dict, then I get the elements in the correct arbitrary order (I hope not accidentally!)

Of course, if I spin my own loop then I can pull the elements in my arbitrary order just fine.

Can anyone illuminate what is the difference between the two (apparently identical) list comprehensions which clearly are not identical.

Code:

from collections import OrderedDict

MAXELEMENT = 8

ElementalSymbols = ['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O']        
ElementalWeights = [1.00794, 4.002602, 6.941, 9.012182, 10.811, 12.0107, 14.0067, 15.9994];

ElementDict= OrderedDict(zip(ElementalSymbols, zip(range(0, MAXELEMENT), ElementalWeights)))

NewOrder = ['Be', 'C', 'H']

# This makes NewList have the same order as ElementDict, not NewOrder.
NewList = [(k, el[1]) for k, el in ElementDict.items() if k in NewOrder]

print NewList
# Results in:
#[('H', 1.00794), ('Be', 9.012182), ('C', 12.0107)]

# We do EXACTLY the same thing but change the OrderedDict to a dict.
ElementDict= dict(ElementDict)
# Same list comprehension, but not it is in NewOrder order instead of ElementDict order.
NewList = [(k, el[1]) for k, el in ElementDict.items() if k in NewOrder]

print NewList
# Results in:
#[('Be', 9.012182), ('C', 12.0107), ('H', 1.00794)]

# And, of course, the kludgy way to do it and be sure the elements are in the right order.
for i, el in enumerate(NewOrder):
    NewList[i] = (NewOrder[i], ElementDict[NewOrder[i]][1])

print NewList
# Results in:
#[('Be', 9.012182), ('C', 12.0107), ('H', 1.00794)]
Was it helpful?

Solution

If you want a specific order, you can do this as the input to the dict, if you do it indirectly as a generator expression to OrderedDict:

MAXELEMENT = 8
ElementalSymbols = ['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O']        
ElementalWeights = [1.00794, 4.002602, 6.941, 9.012182, 10.811, 12.0107, 14.0067, 15.9994];

ElementDict= OrderedDict(zip(ElementalSymbols, zip(range(0, MAXELEMENT), ElementalWeights)))

NewOrder = ['Be', 'C', 'H']

BlueMonday = OrderedDict((x, ElementDict[x]) for x in NewOrder)

print BlueMonday
OrderedDict([('Be', (3, 9.012182)), ('C', (5, 12.0107)), ('H', (0, 1.00794))])
print BlueMonday.items()
[('Be', (3, 9.012182)), ('C', (5, 12.0107)), ('H', (0, 1.00794))]

That's similar to what you are already doing, but maybe a little less kludgy?

OTHER TIPS

If you want random order, you should use the random module, specifically random.sample

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top