dictのキーと値を `unicode`から` str`に変換する最速の方法は?


81

コードの1つの「レイヤー」から、別の「レイヤー」に渡す前にいくつかの計算/変更が実行されるdictを受信して​​います。元のdictのキーと「文字列」値はですがunicode、それらが渡されるレイヤーはstr。のみを受け入れます。

これは頻繁に呼び出されるので、次のようなものを変換するための最速の方法を知りたいと思います。

{ u'spam': u'eggs', u'foo': True, u'bar': { u'baz': 97 } }

...に:

{ 'spam': 'eggs', 'foo': True, 'bar': { 'baz': 97 } }

...「文字列」以外の値は元のタイプのままにする必要があることに注意してください。

何かご意見は?

回答:


151
DATA = { u'spam': u'eggs', u'foo': frozenset([u'Gah!']), u'bar': { u'baz': 97 },
         u'list': [u'list', (True, u'Maybe'), set([u'and', u'a', u'set', 1])]}

def convert(data):
    if isinstance(data, basestring):
        return str(data)
    elif isinstance(data, collections.Mapping):
        return dict(map(convert, data.iteritems()))
    elif isinstance(data, collections.Iterable):
        return type(data)(map(convert, data))
    else:
        return data

print DATA
print convert(DATA)
# Prints:
# {u'list': [u'list', (True, u'Maybe'), set([u'and', u'a', u'set', 1])], u'foo': frozenset([u'Gah!']), u'bar': {u'baz': 97}, u'spam': u'eggs'}
# {'bar': {'baz': 97}, 'foo': frozenset(['Gah!']), 'list': ['list', (True, 'Maybe'), set(['and', 'a', 'set', 1])], 'spam': 'eggs'}

仮定:

  • コレクションモジュールをインポートし、それが提供する抽象基本クラスを利用できます
  • デフォルトのエンコーディングを使用して変換できます(明示的なエンコーディングが必要な場合data.encode('utf-8')ではなく、を使用してstr(data)ください)。

他の種類のコンテナをサポートする必要がある場合は、パターンに従い、それらのケースを追加する方法が明らかであることを願っています。


そして、いくつかの値がリスト/セットなどである場合はどうしますか?
フィリップBオールダム

1
タプルと
フローズンセット

3
なぜtype(data)(map(convert, data))代わりに使用するのmap(convert, data)ですか?
アバソフアレクサンダー2013

4
@AbbasovAlexander:入力したのと同じタイプを取り戻すために、タプルはタプルになり、リストはリストになり、セットはセットになります。
RichieHindle 2013

1
@Moberg:データ構造が何百レベルもの深さでネストされている場合のみ。
RichieHindle 2014年

25

私はこれに遅れていることを知っています:

def convert_keys_to_string(dictionary):
    """Recursively converts dictionary keys to strings."""
    if not isinstance(dictionary, dict):
        return dictionary
    return dict((str(k), convert_keys_to_string(v)) 
        for k, v in dictionary.items())

1
うん、これはそれを行う正しい方法のように思えます、インラインおよび他のバージョンは実際には現実世界のシナリオには十分ではありません。残念ながら、これを達成するための信頼できるインライン再帰のない方法はありません。それとも、python str(...)jsonの規則に基づいているのでしょうか?
jayunit100 2012

1
これは私のお気に入りで、私が探していたのはキーだけを変換することです。小さなタイプミス:返されるdict()引数の周りに追加の()が必要です。
ggll 2013

このソリューションの唯一の問題は、キーがすべての文字列ではない場合(つまり、int型)です
MrWonderful 2016年

@MrWonderfulそしてそれはなぜですか?strintを呼び出すことに問題はありません
Germano 2016年

@Germano:もちろん、intでstr()を呼び出すことはできますが、strを取得します....もはやintではありません。したがって、キーのタイプはintからstrに変更されます。これは、Unicodeをstrに変更するだけではありません。これは元の質問です。
MrWonderful 2016年

13

これをインラインで実行したいが、再帰下降を必要としない場合、これは機能する可能性があります。

DATA = { u'spam': u'eggs', u'foo': True, u'bar': { u'baz': 97 } }
print DATA
# "{ u'spam': u'eggs', u'foo': True, u'bar': { u'baz': 97 } }"

STRING_DATA = dict([(str(k), v) for k, v in data.items()])
print STRING_DATA
# "{ 'spam': 'eggs', 'foo': True, 'bar': { u'baz': 97 } }"

4
次のように2.7以降では、これを簡略化することができます:{ str(key):value for key,value in data.items() }
AnjoMan

4

ネストされていないdictの場合(タイトルにはそのケースが記載されていないため、他の人にとって興味深いかもしれません)

{str(k): str(v) for k, v in my_dict.items()}

1
{STR(K):kのSTR(V)、my_dict.items中のV()}
yardstick17

助けこれは私が私のデータフレームの列と比較するために必要な文字列に私の鍵を変換する
メガマインド

3
def to_str(key, value):
    if isinstance(key, unicode):
        key = str(key)
    if isinstance(value, unicode):
        value = str(value)
    return key, value

キーと値をそれに渡し、内部辞書を説明するためにコードに再帰を追加します。


2

すべてをインライン(非再帰的)にするには:

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

0

使用するだけ print(*(dict.keys()))

*は、リストなどのコンテナを解凍するために使用できます。*の詳細については、このSO回答を確認してください。


このコードは問題を解決するかもしれませんが、良い答えはコードがをするの、そしてそれがどのように役立つのを説明するはずです。
BDL

0
>>> d = {u"a": u"b", u"c": u"d"}
>>> d
{u'a': u'b', u'c': u'd'}
>>> import json
>>> import yaml
>>> d = {u"a": u"b", u"c": u"d"}
>>> yaml.safe_load(json.dumps(d))
{'a': 'b', 'c': 'd'}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.