6

Now that dictionaries are ordered in python 3.6, it must be the case that there is a way to get the first and second values of a dictionary in only two lines. Right now, I have to use 7 lines to accomplish this:

for key, value in class_sent.items():
    i += 1
    if i == 1:
        first_sent = value
    elif i == 2:
        second_sent = value

I also tried:

first_sent = next(iter(class_sent))
    second_sent = next(iter(class_sent))

But in that case the second_sent is equal to the first_sent. If anyone knows how to obtain the first and second values in a dictionary in as few lines as possible I would seriously appreciate it.

Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
bobsmith76
  • 160
  • 1
  • 9
  • 26
  • 1
    For those who wonder: https://stackoverflow.com/q/39980323/7051394. Besides, this (as for now) happens to be an implementation detail for CPython, and is not comprised in Python 3.6's spec. – Right leg Jul 04 '17 at 22:40

2 Answers2

13

Right now Python only guarantees that the order of **kwargs and class attributes are preserved.

Considering that the implementation of Python you're using guarantees this behaviour you could do.

  1. Using itertools.islice.

>>> from itertools import islice    
>>> dct = {'a': 1, 'b': 2, 'c': 3}    
>>> first, second = islice(dct.values(), 2)    
>>> first, second
(1, 2)
  1. Using iter().

>>> it = iter(dct.values())    
>>> first, second = next(it), next(it)    
>>> first, second
(1, 2)
  1. Using extended iterable unpacking(will result in unnecessary unpacking of other values as well):

>>> first, second, *_ = dct.values()
>>> first, second
(1, 2)
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • 1
    Please do emphasize the fact that this is not valid in Python 3.6, but in CPython 3.6. As for now, according to the actual specification, dictionaries are not ordered, so this must no be taken for granted. – Right leg Jul 04 '17 at 22:45
  • Yes. For now it is good practice to explicitly import and use `OrderedDict`, which in Python 3.6 is just a thin wrapper around `dict` now. – juanpa.arrivillaga Jul 04 '17 at 22:47
  • @bobsmith76 note, you could have *always* done this, just that the order would not reflect insertion order. Since being ordered is currently just an implementation detail, you should still use `OrderedDict` if you want your code to be portable. – juanpa.arrivillaga Jul 04 '17 at 22:48
  • Is 1 and 2 O(1) operations ? – user1767754 Jul 04 '17 at 23:05
  • @user1767754 For just 2 items, yes. – Ashwini Chaudhary Jul 04 '17 at 23:09
  • @juanpa, do you mean ordereddict is faster? because dictionaries are not all that fast in comparison to lists. – bobsmith76 Jul 06 '17 at 18:36
  • @bobsmith76 first of all, dictionaries and lists are fast at different things. Python `dicts` are *blazingly fast* at retrieving arbitrary values, and membership testing. And that is O(1). I do *not* mean OrderedDict is faster than a regular `dict`, in Python 3.6, `OrderedDict` is a thin wrapper around `dict`. But you should still use `OrderedDict` if you want to rely on the dictionary being ordered, and you want your code to be portable, because the fact that dictionaries are ordered is a CPython 3.6 *implementation detail*, not a guarantee of the language – juanpa.arrivillaga Jul 06 '17 at 18:40
  • I've noticed that dicts slowed down at retrieving values in python 3.6 in comparison to python 2.7. If you want I can get you some exact figures. If you already believe that then how can I get that speed of retrieving arbitrary values that I had in python 2.7? – bobsmith76 Jul 06 '17 at 18:45
0

This could work:

first_sent, second_sent = list(class_sent.values())[:2]
henneray
  • 449
  • 3
  • 10