13

I am making a group chatting app and I have images associated with the users, so whenever they say something, their image is displayed next to it. I wrote the server in python and the client will be an iOS app. I use a dictionary to store all of the message/image pairs. Whenever my iOS app sends a command to the server (msg:<message), the dictionary adds the image and message to the dictionary like so:dictionary[message] = imageName, which is converted to lists then strings to be sent off in a socket. I would like to add the incoming messages to the start of the dictionary, instead of the end. Something like

#When added to end:
dictionary = {"hello":image3.png}
#new message
dictionary = {"hello":image3.png, "i like py":image1.png}

#When added to start:
dictionary = {"hello":image3.png}
#new message
dictionary = {"i like py":image1.png, "hello":image3.png}

Is there any way to add the object to the start of the dictionary?

Minebomber
  • 1,209
  • 2
  • 12
  • 35
  • A dictionary (if we are talking about the standard Python dictionary) does not have an order. – Ashalynd Jun 21 '15 at 16:44
  • Dictionaries are unsorted. That means, you can not append/prepend element to it. You could use list instead, where you would have `[ ("hello","image3.png") ]`, then you can use `yourList.insert(0, ("i like py":"image1.png"))`, which will insert the message as first (index 0) item – kecer Jun 21 '15 at 16:47
  • This question is slightly different with the duplicated! – Mazdak Jun 21 '15 at 16:48
  • I actually didn't think of that. I decided on using lists because my Python skills are a bit rusty. – Minebomber Jun 21 '15 at 16:54
  • 2
    Python dictionary implementations have been ordered for many years, though this was an implementation detail. As of version 3.7, it is a language requirement to maintain order. – Craig.Feied Jan 14 '21 at 21:18

7 Answers7

25

For the use case described it sounds like a list of tuples would be a better data structure.

However, it has been possible to order a dictionary since Python 3.7. Dictionaries are now ordered by insertion order.

To add an element anywhere other than the end of a dictionary, you need to re-create the dictionary and insert the elements in order. This is pretty simple if you want to add an entry to the start of the dictionary.

# Existing data structure
old_dictionary = {"hello": "image3.png"}

# Create a new dictionary with "I like py" at the start, then
# everything from the old data structure.
new_dictionary = {"i like py": "image1.png"}
new_dictionary.update(old_dictionary)

# new_dictionary is now:
# {'i like py': 'image1.png', 'hello': 'image3.png'}
Craig Anderson
  • 754
  • 1
  • 11
  • 18
  • This is the correct answer. While a dict is unordered, when we process some data that is written from a dict, there is an order. This answer ensures that we can prepend to that data. I'm specifically thinking about JsonLines. – Jiulin Teng Mar 07 '21 at 12:54
9

(python3) good example from Manjeet on geeksforgeeks.org

test_dict = {"Gfg" : 5, "is" : 3, "best" : 10}  
updict = {"pre1" : 4, "pre2" : 8}

# ** operator for packing and unpacking items in order
res = {**updict, **test_dict}
dev J
  • 91
  • 1
  • 2
  • This appears to work properly in terms of putting the dictionaries in the right order, but do you happen to know if that behavior is guaranteed at runtime? – Bill Horvath Aug 31 '21 at 21:31
  • This has some unexpected behavior in four loops that `.update` dosn't. – Miladiouss Oct 06 '22 at 07:09
4

First of all it doesn't added the item at the end of dictionary because dictionaries use hash-table to storing their elements and are unordered. if you want to preserve the order you can use collections.OrderedDict.but it will appends the item at the end of your dictionary. One way is appending that item to the fist of your items then convert it to an Orderd:

>>> from collections import OrderedDict
>>> d=OrderedDict()
>>> for i,j in [(1,'a'),(2,'b')]:
...    d[i]=j
... 
>>> d
OrderedDict([(1, 'a'), (2, 'b')])
>>> d=OrderedDict([(3,'t')]+d.items())
>>> d
OrderedDict([(3, 't'), (1, 'a'), (2, 'b')])

Also as another efficient way if it's not necessary to use a dictionary you can use a deque that allows you to append from both side :

>>> from collections import deque
>>> d=deque()
>>> d.append((1,'a'))
>>> d.append((4,'t'))
>>> d
deque([(1, 'a'), (4, 't')])
>>> d.appendleft((8,'p'))
>>> d
deque([(8, 'p'), (1, 'a'), (4, 't')])
Mazdak
  • 105,000
  • 18
  • 159
  • 188
1

I am not sure that a dictionary is the best data structure for your data, but you may find useful collections.OderedDict. It is basically a dictionary that remembers the order of keys added to the dictionary in a FIFO fashion (which is the opposite of what you need).

If you want to retrieve all your items starting from the most recent one, you can use reversed() to reverse dictionary iterators. You can also use the method popitem() to retrieve (and remove) from the dictionary the key-value pair you last entered.

Link to the docs: https://docs.python.org/2/library/collections.html#collections.OrderedDict

poros
  • 386
  • 3
  • 12
0

As others have pointed out, there is no concept of "order" in a standard dict. Although you can use an OrderedDict to add ordering behavior, this brings other considerations -- unlike a normal dict, isn't a portable data structure (e.g. dumping to JSON then reloading does not preserve order) -- and isn't available in the standard library for all versions of Python.

You might be better off using a sequential key in a standard dict -- a count-up index, or time stamp -- to keep things simple.

Chris Johnson
  • 20,650
  • 6
  • 81
  • 80
0

As others have pointed out, there is no "order" in a dictionary. However, if you are like me and just need a temporary (/ hacky) workaround that works for your purposes. There is a way to do this.

You can iterate the dictionary, and append the item at the beginning of the iteration process. This seemed to work for me.

The relevant part is where new_fields is declared. I am including the rest for context.

userprofile_json = Path(__file__).parents[2] / f"data/seed-data/user-profile.json"

    with open(userprofile_json) as f:
        user_profiles = json.load(f)

    for user_profile in user_profiles:

        new_fields = {
            'user':  user_profile['fields']['username'],
        }
        for k, v in user_profile['fields'].items():
            new_fields[k] = v

        user_profile['fields'] = new_fields


    with open(userprofile_json, 'w') as f:
        json.dump(user_profiles, f, indent=4)

Tomiwa
  • 840
  • 12
  • 14
  • 1
    For Python 3.7+, ordering in dictionaries is [guaranteed to be insertion order](https://docs.python.org/3.7/library/stdtypes.html#dict.values). – ingyhere Dec 21 '20 at 22:55
0

With python 3.9+ (PEP 584) there's an even nicer solution with the | operator.

old_dictionary = {"hello": "image3.png"}
new_dictionary = {"i like py": "image1.png"} | old_dictionary
drakon
  • 125
  • 9