66

I wish to do this but for a dictionary:

"My string".lower()

Is there a built in function or should I use a loop?

Alex W
  • 37,233
  • 13
  • 109
  • 109
Teifion
  • 108,121
  • 75
  • 161
  • 195

14 Answers14

106

You will need to use either a loop or a list/generator comprehension. If you want to lowercase all the keys and values, you can do this::

dict((k.lower(), v.lower()) for k,v in {'My Key':'My Value'}.iteritems())

If you want to lowercase just the keys, you can do this::

dict((k.lower(), v) for k,v in {'My Key':'My Value'}.iteritems())

Generator expressions (used above) are often useful in building dictionaries; I use them all the time. All the expressivity of a loop comprehension with none of the memory overhead.

Rick Copeland
  • 11,672
  • 5
  • 39
  • 38
16

If you want keys and values of multi-nested dictionary (json format) lowercase, this might help. Need to have support for dict comprehensions what should be in Python 2.7

dic = {'A':['XX', 'YY', 'ZZ'],
       'B':(u'X', u'Y', u'Z'),
       'C':{'D':10,
            'E':('X', 'Y', 'Z'),
            'F':{'X', 'Y', 'Z'}
           },
       'G':{'X', 'Y', 'Z'}
      }

PYTHON2.7 -- also supports OrderedDict

def _lowercase(obj):
    """ Make dictionary lowercase """
    if isinstance(obj, dict):
        t = type(obj)()
        for k, v in obj.items():
            t[k.lower()] = _lowercase(v)
        return t
    elif isinstance(obj, (list, set, tuple)):
        t = type(obj)
        return t(_lowercase(o) for o in obj)
    elif isinstance(obj, basestring):
        return obj.lower()
    else:
        return obj 

PYTHON 3.6

def _lowercase(obj):
    """ Make dictionary lowercase """
    if isinstance(obj, dict):
        return {k.lower():_lowercase(v) for k, v in obj.items()}
    elif isinstance(obj, (list, set, tuple)):
        t = type(obj)
        return t(_lowercase(o) for o in obj)
    elif isinstance(obj, str):
        return obj.lower()
    else:
        return obj
vldbnc
  • 429
  • 5
  • 5
  • 1
    in python 3, use items(), instead of iteritems() and str instead of basestring, and if u dont want to lower your values, in my case they were lists, just remove the elif clause that checks list(lists can't be keys anyways) – lava-lava Apr 11 '18 at 19:39
  • this solution is for multi-nested dictionaries. I will add solution as @lava-lava suggested + add checking for set and tuples. In case of 2.7 version small alternation in dict creation to support OrderedDict (in 3.0 dict are ordered by def.) – vldbnc Apr 12 '18 at 21:52
15

Shorter way in python 3: {k.lower(): v for k, v in my_dict.items()}

damio
  • 6,041
  • 3
  • 39
  • 58
14

The following is identical to Rick Copeland's answer, just written without a using generator expression:

outdict = {}
for k, v in {'My Key': 'My Value'}.iteritems():
    outdict[k.lower()] = v.lower()

Generator-expressions, list comprehension's and (in Python 2.7 and higher) dict comprehension's are basically ways of rewriting loops.

In Python 2.7+, you can use a dictionary comprehension (it's a single line of code, but you can reformat them to make it more readable):

{k.lower():v.lower()
    for k, v in
    {'My Key': 'My Value'}.items()
}

They are quite often tidier than the loop equivalent, as you don't have to initialise an empty dict/list/etc.. but, if you need to do anything more than a single function/method call they can quickly become messy.

dbr
  • 165,801
  • 69
  • 278
  • 343
  • how to generalize this for a case where the dictionary has more than one keys and >1 values for each key? – user1993 Dec 30 '16 at 15:29
5

This will lowercase all your dict keys. Even if you have nested dict or lists. You can do something similar to apply other transformations.

def lowercase_keys(obj):
  if isinstance(obj, dict):
    obj = {key.lower(): value for key, value in obj.items()}
    for key, value in obj.items():         
      if isinstance(value, list):
        for idx, item in enumerate(value):
          value[idx] = lowercase_keys(item)
      obj[key] = lowercase_keys(value)
  return obj 
json_str = {"FOO": "BAR", "BAR": 123, "EMB_LIST": [{"FOO": "bar", "Bar": 123}, {"FOO": "bar", "Bar": 123}], "EMB_DICT": {"FOO": "BAR", "BAR": 123, "EMB_LIST": [{"FOO": "bar", "Bar": 123}, {"FOO": "bar", "Bar": 123}]}}

lowercase_keys(json_str)


Out[0]: {'foo': 'BAR',
 'bar': 123,
 'emb_list': [{'foo': 'bar', 'bar': 123}, {'foo': 'bar', 'bar': 123}],
 'emb_dict': {'foo': 'BAR',
  'bar': 123,
  'emb_list': [{'foo': 'bar', 'bar': 123}, {'foo': 'bar', 'bar': 123}]}}
André Sionek
  • 81
  • 1
  • 4
4

I used JSON library to deserialize the dictionary first, apply lower case than convert back to dictionary

import json
mydict = {'UPPERCASE': 'camelValue'}
print(mydict)
mydict_in_str = json.dumps(mydict)
mydict_lowercase = json.loads(mydict_in_str.lower())
print(mydict_lowercase)
zeb
  • 49
  • 2
3

In Python 3:

d = dict()
d = {k.casefold(): v for k, v in d.items()}
Joe Heffer
  • 755
  • 7
  • 9
2

If the dictionary supplied have multiple type of key/values(numeric, string etc.); then use the following solution.

For example; if you have a dictionary named mydict as shown below

mydict = {"FName":"John","LName":"Doe",007:true}

In Python 2.x

dict((k.lower() if isinstance(k, basestring) else k, v.lower() if isinstance(v, basestring) else v) for k,v in mydict.iteritems())

In Python 3.x

dict((k.lower() if isinstance(k, str) else k, v.lower() if isinstance(v, str) else v) for k,v in mydict.iteritems())

Note: this works good on single dimensional dictionaries

Finny Abraham
  • 850
  • 7
  • 12
  • At this point I would just make a lower function which does the check. `try_lower = lambda k: k.lower() if isinstance(k, str) else k` – Will S Feb 01 '16 at 10:11
2

I am answering this late - as the question is tagged Python. Hence answering with a solution for both Python 2.x and Python 3.x, and also handling the case of non-string keys.

Python 2.x - using dictionary comprehension

{k.lower() if isinstance(k, basestring) else k: v.lower() if isinstance(v, basestring) else v for k,v in yourDict.iteritems()}

Demo:

>>> yourDict = {"Domain":"WORKGROUP", "Name": "CA-LTP-JOHN", 111: 'OK', "Is_ADServer": 0, "Is_ConnectionBroker": 0, "Domain_Pingable": 0}
>>> {k.lower() if isinstance(k, basestring) else k: v.lower() if isinstance(v, basestring) else v for k,v in yourDict.iteritems()}
{'domain': 'workgroup', 'name': 'ca-ltp-john', 'is_adserver': 0, 'is_connectionbroker': 0, 111: 'ok', 'domain_pingable': 0}

Python 3.x - no iteritems() in Python 3.x

{k.lower() if isinstance(k, str) else k: v.lower() if isinstance(v, str) else v for k,v in yourDict.items()}

Demo:

>>> dict((k.lower() if isinstance(k, basestring) else k, v.lower() if isinstance(v, basestring) else v) for k,v in yourDict.iteritems())
Traceback (most recent call last):
  File "python", line 1, in <module>
AttributeError: 'dict' object has no attribute 'iteritems'
>>> {k.lower() if isinstance(k, str) else k: v.lower() if isinstance(v, str) else v for k,v in yourDict.items()}
>>> {'domain': 'workgroup', 'name': 'ca-ltp-john', 111: 'ok', 'is_adserver': 0, 'is_connectionbroker': 0, 'domain_pingable': 0}
Nabeel Ahmed
  • 18,328
  • 4
  • 58
  • 63
1

Love the way you can use multilevel functions, here's my way of lowercase-ing the keys

def to_lower(dictionary):

    def try_iterate(k):
        return lower_by_level(k) if isinstance(k, dict) else k

    def try_lower(k):
        return k.lower() if isinstance(k, str) else k

    def lower_by_level(data):
        return dict((try_lower(k), try_iterate(v)) for k, v in data.items())

    return lower_by_level(dictionary)
Decebal
  • 1,376
  • 1
  • 21
  • 36
1

In Python 3 you can do:

dict((k.lower(), v.lower()) for k,v in {'Key':'Value'}.items())

In Python 2 just substitute .items() for .iteritems():

dict((k.lower(), v.lower()) for k,v in {'Key':'Value'}.iteritems())
Ralf
  • 16,086
  • 4
  • 44
  • 68
vasista
  • 184
  • 1
  • 10
1

An option is to subtype from UserDict, and that way all data inserted will have lower case key and you don't need to care about to lower case at access time:

from collections import UserDict
from typing import Any

class InsensitiveCaseDict(UserDict):
    def __getitem__(self, key: Any) -> Any:
        if type(key) is str:
            return super().__getitem__(key.lower())
        return super().__getitem__(key)

    def __setitem__(self, key: Any, item: Any) -> Any:
        if type(key) is str:
            self.data[key.lower()] = item
            return
        self.data[key] = item

And you can convert your original dict:

lowercase_dict = InsensitiveCaseDict(my_original_dict)
erickod
  • 51
  • 7
0

In addition to @vldbnc answer, if you only want to lowercase the keys only in a nested dict in python 3.x

def _dict_keys_lowercase(obj):
    """ Make dictionary lowercase """
    if isinstance(obj, dict):
        return {k.lower():_dict_keys_lowercase(v) for k, v in obj.items()}
    else:
        return obj
shadowbq
  • 1,232
  • 1
  • 16
  • 29
-1
def convert_to_lower_case(data):
    if type(data) is dict:
        for k, v in data.iteritems():
            if type(v) is str:
                data[k] = v.lower()
            elif type(v) is list:
                data[k] = [x.lower() for x in v]
            elif type(v) is dict:
                data[k] = convert_to_lower_case(v)
    return data
sree
  • 1