How to insert key-value pair into dictionary at a specified position?

31,875

Solution 1

On python < 3.7 (or cpython < 3.6), you cannot control the ordering of pairs in a standard dictionary.

If you plan on performing arbitrary insertions often, my suggestion would be to use a list to store keys, and a dict to store values.

mykeys = ['Name', 'Age', 'Class']
mydict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'} # order doesn't matter

k, v = 'Phone', '123-456-7890'

mykeys.insert(mykeys.index('Name')+1, k)
mydict[k] = v

for k in mykeys:
    print(f'{k} => {mydict[k]}')

# Name => Zara
# Phone => 123-456-7890
# Age => 7
# Class => First

If you plan on initialising a dictionary with ordering whose contents are not likely to change, you can use the collections.OrderedDict structure which maintains insertion order.

from collections import OrderedDict

data = [('Name', 'Zara'), ('Phone', '1234'), ('Age', 7), ('Class', 'First')] 
odict = OrderedDict(data)
odict
# OrderedDict([('Name', 'Zara'),
#              ('Phone', '1234'),
#              ('Age', 7),
#              ('Class', 'First')])

Note that OrderedDict does not support insertion at arbitrary positions (it only remembers the order in which keys are inserted into the dictionary).

Solution 2

You will have to initialize your dict as OrderedDict. Create a new empty OrderedDict, go through all keys of the original dictionary and insert before/after when the key name matches.

from pprint import pprint
from collections import OrderedDict


def insert_key_value(a_dict, key, pos_key, value):
    new_dict = OrderedDict()
    for k, v in a_dict.items():
        if k==pos_key:
            new_dict[key] = value  # insert new key
        new_dict[k] = v
    return new_dict


mydict = OrderedDict([('Name', 'Zara'), ('Age', 7), ('Class', 'First')])
my_new_dict = insert_key_value(mydict, "Phone", "Age", "1234")
pprint(my_new_dict)

Solution 3

Had the same issue and solved this as described below without any additional imports being required and only a few lines of code. Tested with Python 3.6.9.

  1. Get position of key 'Age' because the new key value pair should get inserted before
  2. Get dictionary as list of key value pairs
  3. Insert new key value pair at specific position
  4. Create dictionary from list of key value pairs
mydict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
print(mydict)
# {'Name': 'Zara', 'Age': 7, 'Class': 'First'}

pos = list(mydict.keys()).index('Age')
items = list(mydict.items())
items.insert(pos, ('Phone', '123-456-7890'))
mydict = dict(items)

print(mydict)
# {'Name': 'Zara', 'Phone': '123-456-7890', 'Age': 7, 'Class': 'First'}

Edit 2021-12-20:
Just saw that there is an insert method available ruamel.yaml, see the example from the project page:

import sys
from ruamel.yaml import YAML

yaml_str = """\
first_name: Art
occupation: Architect  # This is an occupation comment
about: Art Vandelay is a fictional character that George invents...
"""

yaml = YAML()
data = yaml.load(yaml_str)
data.insert(1, 'last name', 'Vandelay', comment="new key")
yaml.dump(data, sys.stdout)

Solution 4

This is a follow-up on nurp's answer. Has worked for me, but offered with no warranty.

# Insert dictionary item into a dictionary at specified position: 
def insert_item(dic, item={}, pos=None):
    """
    Insert a key, value pair into an ordered dictionary.
    Insert before the specified position.
    """
    from collections import OrderedDict
    d = OrderedDict()
    # abort early if not a dictionary:
    if not item or not isinstance(item, dict):
        print('Aborting. Argument item must be a dictionary.')
        return dic
    # insert anywhere if argument pos not given: 
    if not pos:
        dic.update(item)
        return dic
    for item_k, item_v in item.items():
        for k, v in dic.items():
            # insert key at stated position:
            if k == pos:
                d[item_k] = item_v
            d[k] = v
    return d

d = {'A':'letter A', 'C': 'letter C'}
insert_item(['A', 'C'], item={'B'})
## Aborting. Argument item must be a dictionary.

insert_item(d, item={'B': 'letter B'})
## {'A': 'letter A', 'C': 'letter C', 'B': 'letter B'}

insert_item(d, pos='C', item={'B': 'letter B'})
# OrderedDict([('A', 'letter A'), ('B', 'letter B'), ('C', 'letter C')])

Solution 5

Would this be "pythonic"?

def add_item(d, new_pair, old_key): #insert a newPair (key, value) after old_key
    n=list(d.keys()).index(old_key)
    return {key:d.get(key,new_pair[1]) for key in list(d.keys())[:n+1] +[new_pair[0]] + list(d.keys())[n+1:] }

INPUT: new_pair=('Phone',1234) , old_key='Age'

OUTPUT: {'Name': 'Zara', 'Age': 7, 'Phone': 1234, 'Class': 'First'}

Share:
31,875

Related videos on Youtube

DeepApp
Author by

DeepApp

Updated on July 18, 2022

Comments

  • DeepApp
    DeepApp almost 2 years

    How would I insert a key-value pair at a specified location in a python dictionary that was loaded from a YAML document?

    For example if a dictionary is:

    dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}

    I wish to insert the element 'Phone':'1234' before 'Age', and after 'Name' for example. The actual dictionary I shall be working on is quite large (parsed YAML file), so deleting and reinserting might be a bit cumbersome (I don't really know).

    If I am given a way of inserting into a specified position in an OrderedDict, that would be okay, too.

  • DeepApp
    DeepApp almost 7 years
    The problem is yaml.load loads a yaml file as a dictionary of dictionaries... (and so on). So editing has to be done on dictionaries.
  • cs95
    cs95 almost 7 years
    @DeepApp. The solution is simple. Convert the dict to a list. Example: dictAsList = [(k, v) for k, v in yourDict.items()]. Now you just need to iterate over your dictAsList and insert your items where you like.
  • Anthon
    Anthon almost 7 years
    If you start with YAML, you will not necessarily preserve the key order as is available from the YAML document if you do this. It is much preferable to use the RoundTripLoader if you want to preserve the order, it was made (among other things) for that purpose.
  • Boris Verkhovskiy
    Boris Verkhovskiy over 4 years
    Not on CPython 3.6 or any other Python 3.7. dicts keep insertion order now, there's no need to use OrderedDict for this
  • andreis11
    andreis11 about 4 years
    Does not address the question : "specified location"