ধরুন আপনার কাছে এর মতো একটি অভিধান রয়েছে:
{'a': 1,
'c': {'a': 2,
'b': {'x': 5,
'y' : 10}},
'd': [1, 2, 3]}
আপনি কীভাবে এমন কিছুতে চাটুকার করতে যাবেন:
{'a': 1,
'c_a': 2,
'c_b_x': 5,
'c_b_y': 10,
'd': [1, 2, 3]}
ধরুন আপনার কাছে এর মতো একটি অভিধান রয়েছে:
{'a': 1,
'c': {'a': 2,
'b': {'x': 5,
'y' : 10}},
'd': [1, 2, 3]}
আপনি কীভাবে এমন কিছুতে চাটুকার করতে যাবেন:
{'a': 1,
'c_a': 2,
'c_b_x': 5,
'c_b_y': 10,
'd': [1, 2, 3]}
উত্তর:
মূলত আপনি একইভাবে নেস্টেড তালিকা সমতল করতে চান, আপনাকে কেবল কী / মান দ্বারা ডিকটি পুনরুক্তকরণ, আপনার নতুন অভিধানের জন্য নতুন কী তৈরি করা এবং চূড়ান্ত পদক্ষেপে অভিধান তৈরি করার জন্য অতিরিক্ত কাজ করতে হবে।
import collections
def flatten(d, parent_key='', sep='_'):
items = []
for k, v in d.items():
new_key = parent_key + sep + k if parent_key else k
if isinstance(v, collections.MutableMapping):
items.extend(flatten(v, new_key, sep=sep).items())
else:
items.append((new_key, v))
return dict(items)
>>> flatten({'a': 1, 'c': {'a': 2, 'b': {'x': 5, 'y' : 10}}, 'd': [1, 2, 3]})
{'a': 1, 'c_a': 2, 'c_b_x': 5, 'd': [1, 2, 3], 'c_b_y': 10}
isinstance
কোনও try..except
ব্লক দিয়ে প্রতিস্থাপন করেন তবে এটি যে কোনও ম্যাপিংয়ের জন্য কাজ করবে, তা এখান থেকে উত্পন্ন না হলেও dict
।
collections.MutableMapping
এটিকে আরও জেনেরিক করার জন্য এটি পরীক্ষায় পরিবর্তন করেছে । তবে পাইথনের জন্য <2.6, try..except
সম্ভবত সেরা বিকল্প।
if isinstance(v, collections.MutableMapping):
করতেif v and isinstance(v, collections.MutableMapping):
new_key = parent_key + sep + k if parent_key else k
ধরে নেওয়া হয়েছে যে কীগুলি সর্বদা স্ট্রিং হয়, অন্যথায় এটি উত্থাপন করবে TypeError: cannot concatenate 'str' and [other] objects
। তবে, আপনি কেবল k
স্ট্রিং ( str(k)
), বা স্ট্রিংয়ের পরিবর্তে টিপলে কী চাপিয়ে (টিউপসগুলি ডিক কীও হতে পারে) দ্বারা এটি স্থির করতে পারেন।
মূল পোস্টারটি বিবেচনা করার জন্য দুটি বড় বিবেচ্য বিষয় রয়েছে:
{'a_b':{'c':1}, 'a':{'b_c':2}}
ফলাফল হবে {'a_b_c':???}
। নীচের সমাধানটি জোড়ের পুনরাবৃত্তিযোগ্য ফিরিয়ে সমস্যাটি থেকে মুক্তি দেয়।joinedKey = '_'.join(*keys)
তবে এটির জন্য আপনার ও (N ^ 2) ব্যয় করতে হবে। তবে আপনি যদি বলতে ইচ্ছুক হন তবে nextKey = previousKey+'_'+thisKey
এটি আপনাকে ও (এন) সময় দেয়। নীচের সমাধানটি আপনাকে উভয়ই করতে দেয় (যেহেতু আপনি কেবল সমস্ত কীগুলি একত্রিত করতে পারেন, তারপরে সেগুলি পোস্টপ্রসেস করুন)।(পারফরম্যান্স সম্ভবত কোনও সমস্যা নয়, তবে অন্য কেউ যত্ন নেওয়ার ক্ষেত্রে আমি দ্বিতীয় পয়েন্টটি বিস্তারিতভাবে বর্ণনা করব: এটি বাস্তবায়নের ক্ষেত্রে, অনেক বিপজ্জনক পছন্দ রয়েছে you আপনি যদি এটি পুনরাবৃত্তভাবে করেন এবং ফলন এবং পুনরায় ফলন দেন, বা সমান কিছু যা স্পর্শ করে একাধিকবার নোড (যা ঘটনাক্রমে করতে বেশ সহজ), আপনি সম্ভাব্য O (n ^ 2) বরং হে (ঢ) চেয়ে কাজ করছেন। এর কারণ হতে পারে আপনি একটি কী গণনা করছি a
তারপর a_1
তারপর a_1_i
..., এবং তারপর গণক a
তারপর a_1
তারপর a_1_ii
..., কিন্তু সত্যিই আপনি নিরূপণ করা না a_1
আবার। এমনকি যদি আপনি এটা পুনঃগণনা করা হয় না, পুনরায় ফলনশীল এটা (একটি 'লেভেল দ্বারা পর্যায়ের' পদ্ধতি) একটি ভাল উদাহরণ ঠিক যেমন খারাপ। হয় পারফরম্যান্স সম্পর্কে চিন্তা করতে {1:{1:{1:{1:...(N times)...{1:SOME_LARGE_DICTIONARY_OF_SIZE_N}...}}}}
)
নীচে আমি একটি ফাংশন লিখেছি flattenDict(d, join=..., lift=...)
যা অনেকগুলি উদ্দেশ্যে অভিযোজিত হতে পারে এবং আপনি যা করতে পারেন তা করতে পারেন। দুঃখের বিষয় হচ্ছে উপরের পারফরম্যান্সের জরিমানা ব্যয় না করে এই ফাংশনের একটি অলস সংস্করণ তৈরি করা মোটামুটি শক্ত (চেইন.ফর্ম_ট্রেটেবলের মতো অনেক অজগর বিল্টিনগুলি আসলে দক্ষ নয়, যা আমি কেবল স্থায়ী হওয়ার আগে এই কোডটির তিনটি পৃথক সংস্করণের ব্যাপক পরীক্ষার পরে উপলব্ধি করেছিলাম) এইটা).
from collections import Mapping
from itertools import chain
from operator import add
_FLAG_FIRST = object()
def flattenDict(d, join=add, lift=lambda x:x):
results = []
def visit(subdict, results, partialKey):
for k,v in subdict.items():
newKey = lift(k) if partialKey==_FLAG_FIRST else join(partialKey,lift(k))
if isinstance(v,Mapping):
visit(v, results, newKey)
else:
results.append((newKey,v))
visit(d, results, _FLAG_FIRST)
return results
কী চলছে তা আরও ভালভাবে বুঝতে, নীচে reduce
(বাম) সাথে অপরিচিতদের জন্য একটি চিত্র রয়েছে যা অন্যথায় "ভাঁজ বাম" নামে পরিচিত। কখনও কখনও এটি কে 0 এর জায়গায় প্রাথমিক মান দিয়ে আঁকা হয় (তালিকার অংশ নয়, ফাংশনটিতে স্থান পেয়েছে)। এখানে,J
আমাদের join
ফাংশন। আমরা প্রতিটি কে এন সাথে প্রিপ্রোসেস করি lift(k)
।
[k0,k1,...,kN].foldleft(J)
/ \
... kN
/
J(k0,J(k1,J(k2,k3)))
/ \
/ \
J(J(k0,k1),k2) k3
/ \
/ \
J(k0,k1) k2
/ \
/ \
k0 k1
এটি বাস্তবে একইরকম functools.reduce
তবে আমাদের ফাংশনটি গাছের সমস্ত কী-পাথগুলিতে এটি করে।
>>> reduce(lambda a,b:(a,b), range(5))
((((0, 1), 2), 3), 4)
বিক্ষোভ (যা আমি অন্যথায় ডকাস্ট্রিংয়ে রেখেছি):
>>> testData = {
'a':1,
'b':2,
'c':{
'aa':11,
'bb':22,
'cc':{
'aaa':111
}
}
}
from pprint import pprint as pp
>>> pp(dict( flattenDict(testData, lift=lambda x:(x,)) ))
{('a',): 1,
('b',): 2,
('c', 'aa'): 11,
('c', 'bb'): 22,
('c', 'cc', 'aaa'): 111}
>>> pp(dict( flattenDict(testData, join=lambda a,b:a+'_'+b) ))
{'a': 1, 'b': 2, 'c_aa': 11, 'c_bb': 22, 'c_cc_aaa': 111}
>>> pp(dict( (v,k) for k,v in flattenDict(testData, lift=hash, join=lambda a,b:hash((a,b))) ))
{1: 12416037344,
2: 12544037731,
11: 5470935132935744593,
22: 4885734186131977315,
111: 3461911260025554326}
কর্মক্ষমতা:
from functools import reduce
def makeEvilDict(n):
return reduce(lambda acc,x:{x:acc}, [{i:0 for i in range(n)}]+range(n))
import timeit
def time(runnable):
t0 = timeit.default_timer()
_ = runnable()
t1 = timeit.default_timer()
print('took {:.2f} seconds'.format(t1-t0))
>>> pp(makeEvilDict(8))
{7: {6: {5: {4: {3: {2: {1: {0: {0: 0,
1: 0,
2: 0,
3: 0,
4: 0,
5: 0,
6: 0,
7: 0}}}}}}}}}
import sys
sys.setrecursionlimit(1000000)
forget = lambda a,b:''
>>> time(lambda: dict(flattenDict(makeEvilDict(10000), join=forget)) )
took 0.10 seconds
>>> time(lambda: dict(flattenDict(makeEvilDict(100000), join=forget)) )
[1] 12569 segmentation fault python
... দীর্ঘশ্বাস ফেলো, একথা আমার দোষ বলে মনে করো না ...
[সংযোজন সংক্রান্ত সমস্যার কারণে গুরুত্বহীন historicalতিহাসিক নোট]
পাইথনের তালিকাগুলির অভিধানের অভিধান (২ স্তরের গভীর) একটি ফ্ল্যাটনের কথিত সদৃশ সম্পর্কে :
এই প্রশ্নের সমাধানটি এর মাধ্যমে কার্যকর করা যেতে পারে sorted( sum(flatten(...),[]) )
। বিপরীত সম্ভব নয়: যখন এটি সত্যি যে মান এর flatten(...)
একটি উচ্চ-অর্ডার সঁচায়ক ম্যাপিং দ্বারা কথিত ডুপ্লিকেট থেকে উদ্ধার করা সম্ভব, এক চাবি পুনরুদ্ধার করতে পারবেন না। (সম্পাদনা করুন: এছাড়াও এটি প্রমাণিত হয়েছে যে কথিত সদৃশ মালিকের প্রশ্নটি সম্পূর্ণ আলাদা, কারণ এটি কেবলমাত্র 2-স্তর গভীর অভিধানে ডিল করে, যদিও এই পৃষ্ঠার উত্তরগুলির মধ্যে একটি সাধারণ সমাধান দেয়))
অথবা আপনি যদি ইতিমধ্যে পান্ডা ব্যবহার করেন তবে আপনি এটির json_normalize()
মতো করে এটি করতে পারেন:
import pandas as pd
d = {'a': 1,
'c': {'a': 2, 'b': {'x': 5, 'y' : 10}},
'd': [1, 2, 3]}
df = pd.io.json.json_normalize(d, sep='_')
print(df.to_dict(orient='records')[0])
আউটপুট:
{'a': 1, 'c_a': 2, 'c_b_x': 5, 'c_b_y': 10, 'd': [1, 2, 3]}
আপনি যদি ব্যবহার pandas
করেন তবে একটি ফাংশন লুকিয়ে আছেpandas.io.json._normalize
1 নামক nested_to_record
যা এই ঠিক আছে।
from pandas.io.json._normalize import nested_to_record
flat = nested_to_record(my_dict, sep='_')
1 পান্ডাস সংস্করণ 0.24.x
এবং পুরানো ব্যবহারেpandas.io.json.normalize
(ছাড়া _
)
from pandas.io.json._normalize import nested_to_record
। এর _
আগে আন্ডারস্কোরটি লক্ষ করুন normalize
।
0.25.x
, আমি উত্তর আপডেট করেছি। :)
এখানে এক ধরণের "ক্রিয়ামূলক", "ওয়ান-লাইনার" বাস্তবায়ন রয়েছে। এটি পুনরাবৃত্তিযোগ্য এবং শর্তাধীন অভিব্যক্তি এবং ডিক বোঝার উপর ভিত্তি করে।
def flatten_dict(dd, separator='_', prefix=''):
return { prefix + separator + k if prefix else k : v
for kk, vv in dd.items()
for k, v in flatten_dict(vv, separator, kk).items()
} if isinstance(dd, dict) else { prefix : dd }
টেস্ট:
In [2]: flatten_dict({'abc':123, 'hgf':{'gh':432, 'yu':433}, 'gfd':902, 'xzxzxz':{"432":{'0b0b0b':231}, "43234":1321}}, '.')
Out[2]:
{'abc': 123,
'gfd': 902,
'hgf.gh': 432,
'hgf.yu': 433,
'xzxzxz.432.0b0b0b': 231,
'xzxzxz.43234': 1321}
('hgf',2)
TypeError
+
অপারেটর সমর্থন করে বলে ধরে নিয়েছে । অন্য যে কোনও কিছুর জন্য আপনাকে prefix + separator + k
অবজেক্টগুলি রচনা করতে উপযুক্ত ফাংশন কলের সাথে খাপ খাইয়ে নিতে হবে।
{'a_b':{'c':1}, 'a':{'b_c':2}}
{'name': 'Steven', 'children': [{'name': 'Jessica', 'children': []}, {'name': 'George', 'children': []}]}
কোড:
test = {'a': 1, 'c': {'a': 2, 'b': {'x': 5, 'y' : 10}}, 'd': [1, 2, 3]}
def parse_dict(init, lkey=''):
ret = {}
for rkey,val in init.items():
key = lkey+rkey
if isinstance(val, dict):
ret.update(parse_dict(val, key+'_'))
else:
ret[key] = val
return ret
print(parse_dict(test,''))
ফলাফল:
$ python test.py
{'a': 1, 'c_a': 2, 'c_b_x': 5, 'd': [1, 2, 3], 'c_b_y': 10}
আমি পাইথন 3.2 ব্যবহার করছি, অজগরটির সংস্করণটির জন্য আপডেট করুন।
lkey=''
ফাংশনটি কল করার পরিবর্তে আপনার ফাংশন সংজ্ঞায় এর ডিফল্ট মান নির্দিষ্ট করতে চান । এই বিষয়ে অন্যান্য উত্তর দেখুন।
পাইথন 3.5-এ একটি কার্যকরী এবং পারফরম্যান্ট সমাধান সম্পর্কে কীভাবে ?
from functools import reduce
def _reducer(items, key, val, pref):
if isinstance(val, dict):
return {**items, **flatten(val, pref + key)}
else:
return {**items, pref + key: val}
def flatten(d, pref=''):
return(reduce(
lambda new_d, kv: _reducer(new_d, *kv, pref),
d.items(),
{}
))
এটি আরও বেশি পারফরম্যান্ট:
def flatten(d, pref=''):
return(reduce(
lambda new_d, kv: \
isinstance(kv[1], dict) and \
{**new_d, **flatten(kv[1], pref + kv[0])} or \
{**new_d, pref + kv[0]: kv[1]},
d.items(),
{}
))
ব্যাবহৃত হচ্ছে:
my_obj = {'a': 1, 'c': {'a': 2, 'b': {'x': 5, 'y': 10}}, 'd': [1, 2, 3]}
print(flatten(my_obj))
# {'d': [1, 2, 3], 'cby': 10, 'cbx': 5, 'ca': 2, 'a': 1}
reduce
আপনাকে অভিধানগুলি হ্রাস করার প্রয়োজনে দুর্দান্ত বলে মনে করি । আমি উত্তর আপডেট। এখন আরও কিছুটা অজগর দেখানো উচিত।
এটি অভিধানে সীমাবদ্ধ নয়, প্রতিটি ম্যাপিং টাইপ যা .items () প্রয়োগ করে। এটি যদি শর্তটিকে এড়িয়ে যায় তবে আরও তাত্পর্যপূর্ণ। তবুও ক্রেডিট ইমরানের কাছে যায়:
def flatten(d, parent_key=''):
items = []
for k, v in d.items():
try:
items.extend(flatten(v, '%s%s_' % (parent_key, k)).items())
except AttributeError:
items.append(('%s%s' % (parent_key, k), v))
return dict(items)
d
তা নয় dict
তবে কাস্টম ম্যাপিংয়ের ধরণ যা কার্যকর করে না তবে items
আপনার ফাংশনটি ঠিক তখনই সেখানে ব্যর্থ হবে। সুতরাং, এটি প্রতিটি ম্যাপিং প্রকারের জন্য কাজ করে না কেবল তাদের প্রয়োগ করে items()
।
items
? আমি একটি দেখতে আগ্রহী হতে হবে।
আমার পাইথন ৩.৩ সমাধান জেনারেটর ব্যবহার করে:
def flattenit(pyobj, keystring=''):
if type(pyobj) is dict:
if (type(pyobj) is dict):
keystring = keystring + "_" if keystring else keystring
for k in pyobj:
yield from flattenit(pyobj[k], keystring + k)
elif (type(pyobj) is list):
for lelm in pyobj:
yield from flatten(lelm, keystring)
else:
yield keystring, pyobj
my_obj = {'a': 1, 'c': {'a': 2, 'b': {'x': 5, 'y': 10}}, 'd': [1, 2, 3]}
#your flattened dictionary object
flattened={k:v for k,v in flattenit(my_obj)}
print(flattened)
# result: {'c_b_y': 10, 'd': [1, 2, 3], 'c_a': 2, 'a': 1, 'c_b_x': 5}
নেস্টেড অভিধানগুলি সমতল করার সহজ ফাংশন। পাইথন 3 জন্য, প্রতিস্থাপন .iteritems()
সঙ্গে.items()
def flatten_dict(init_dict):
res_dict = {}
if type(init_dict) is not dict:
return res_dict
for k, v in init_dict.iteritems():
if type(v) == dict:
res_dict.update(flatten_dict(v))
else:
res_dict[k] = v
return res_dict
ধারণা / প্রয়োজনীয়তাটি ছিল: কোনও পিতা-মাতার কী না রেখে সমতল অভিধান পান।
ব্যবহারের উদাহরণ:
dd = {'a': 3,
'b': {'c': 4, 'd': 5},
'e': {'f':
{'g': 1, 'h': 2}
},
'i': 9,
}
flatten_dict(dd)
>> {'a': 3, 'c': 4, 'd': 5, 'g': 1, 'h': 2, 'i': 9}
প্যারেন্ট কীগুলি রাখাও সহজ।
পুনরাবৃত্তির ব্যবহার, এটিকে সহজ এবং মানব পাঠযোগ্য:
def flatten_dict(dictionary, accumulator=None, parent_key=None, separator="."):
if accumulator is None:
accumulator = {}
for k, v in dictionary.items():
k = f"{parent_key}{separator}{k}" if parent_key else k
if isinstance(v, dict):
flatten_dict(dictionary=v, accumulator=accumulator, parent_key=k)
continue
accumulator[k] = v
return accumulator
কলটি সহজ:
new_dict = flatten_dict(dictionary)
অথবা
new_dict = flatten_dict(dictionary, separator="_")
যদি আমরা ডিফল্ট বিভাজক পরিবর্তন করতে চান।
একটু ভাঙ্গন:
যখন ফাংশনটি প্রথম কল করা হয়, তখন এটি কেবল dictionary
আমাদের সমতল করতে চাই পাস করার জন্য বলা হয়। accumulator
প্যারামিটার সমর্থন পুনরাবৃত্তির, যা আমরা পরে দেখতে এখানে। সুতরাং, আমরা accumulator
একটি খালি অভিধানে ইনস্ট্যান্ট করব যেখানে আমরা নেস্টেড সমস্ত মানটিকে মূল থেকে রেখে দেব dictionary
।
if accumulator is None:
accumulator = {}
আমরা অভিধানের মানগুলি পুনরুক্তি করার সাথে সাথে প্রতিটি মানের জন্য একটি কী তৈরি করি। parent_key
যুক্তি হতে হবে None
, প্রথম কলের জন্য যখন যে নেস্টেড অভিধান জন্য, এটা মসিউর কী এটি এর প্রতি নির্দেশ উপস্থিত থাকবে, তাই আমরা যে কী পূর্বে লিখুন।
k = f"{parent_key}{separator}{k}" if parent_key else k
যদি মান v
কী k
প্রতি নির্দেশ করা হয় একটি অভিধান আছে, ফাংশন নিজেই কল নেস্টেড অভিধান ক্ষণস্থায়ী, accumulator
(রেফারেন্স দ্বারা পাস করা হয়েছে যা সকল পরিবর্তন এটি সম্পন্ন একই উদাহরণস্বরূপ সম্পন্ন হয়) এবং কী k
, যাতে আমরা সংক্ষিপ্ত কী তৈরি করতে পারে। continue
বিবৃতি লক্ষ্য করুন । আমরা if
ব্লকের বাইরে, পরবর্তী পংক্তিটি এড়িয়ে যেতে চাই , যাতে নীড়যুক্ত অভিধানটি accumulator
আন্ডার কীতে শেষ না হয় k
।
if isinstance(v, dict):
flatten_dict(dict=v, accumulator=accumulator, parent_key=k)
continue
সুতরাং, মানটি v
অভিধান না হলে আমরা কী করব ? শুধু এটির ভিতরে অপরিবর্তিত রাখুন accumulator
।
accumulator[k] = v
একবার হয়ে গেলে আমরা accumulator
আসলটি রেখে কেবল ফিরে আসিdictionary
যুক্তিটি স্পর্শ না আসি।
বিঃদ্রঃ
এটি কেবল অভিধানগুলির সাথে কাজ করবে যেখানে কী হিসাবে স্ট্রিং রয়েছে। __repr__
পদ্ধতিটি বাস্তবায়িত করতে পারে হ্যাশযোগ্য বস্তুগুলির সাথে এটি কাজ করবে তবে অযাচিত ফলাফল পাবে।
এটি ইমরানের এবং রালুর উত্তর উভয়ের সাথে মিল। এটি কোনও জেনারেটর ব্যবহার করে না, পরিবর্তে একটি বন্ধের সাথে পুনরাবৃত্তি নিয়োগ করে:
def flatten_dict(d, separator='_'):
final = {}
def _flatten_dict(obj, parent_keys=[]):
for k, v in obj.iteritems():
if isinstance(v, dict):
_flatten_dict(v, parent_keys + [k])
else:
key = separator.join(parent_keys + [k])
final[key] = v
_flatten_dict(d)
return final
>>> print flatten_dict({'a': 1, 'c': {'a': 2, 'b': {'x': 5, 'y' : 10}}, 'd': [1, 2, 3]})
{'a': 1, 'c_a': 2, 'c_b_x': 5, 'd': [1, 2, 3], 'c_b_y': 10}
_flatten_dict
কখনই ফিরে আসে না এবং এটি কখনই ফিরে আসবে বলে আশা করা যায় না। এটি সম্ভবত একটি subfunction বা পরিবর্তে একটি সংযুক্ত ফাংশন হিসাবে উল্লেখ করা যেতে পারে ।
দাউদের সমাধান খুব সুন্দর তবে সন্তোষজনক ফলাফল দেয় না যখন নেস্টেড ডিকটিতে ডিক্টের তালিকা থাকে তবে তার কোডটি সেই ক্ষেত্রে মানিয়ে নেওয়া যায়:
def flatten_dict(d):
items = []
for k, v in d.items():
try:
if (type(v)==type([])):
for l in v: items.extend(flatten_dict(l).items())
else:
items.extend(flatten_dict(v).items())
except AttributeError:
items.append((k, v))
return dict(items)
type([])
প্রতিটি আইটেমের জন্য একটি ফাংশন কল এড়ানোর জন্য ফলাফলটি ক্যাশে করতে পারেন dict
।
isinstance(v, list)
পরিবর্তে ব্যবহার করুন
উপরের উত্তরগুলি সত্যই ভাল কাজ করে। কেবল ভেবেছি যে আমি লিখেছি এমন অপরিচ্ছন্ন ফাংশন যুক্ত করব:
def unflatten(d):
ud = {}
for k, v in d.items():
context = ud
for sub_key in k.split('_')[:-1]:
if sub_key not in context:
context[sub_key] = {}
context = context[sub_key]
context[k.split('_')[-1]] = v
return ud
দ্রষ্টব্য: এটি চাবিতে ইতিমধ্যে উপস্থিত '_' এর জন্য অ্যাকাউন্ট করে না, অনেকটা সমতল অংশগুলির মতো।
এখানে মার্জিত, স্থান প্রতিস্থাপনের জন্য একটি অ্যালগরিদম। পাইথন ২.7 এবং পাইথন ৩.৫ নিয়ে পরীক্ষা করেছেন। বিভাজক হিসাবে বিন্দু অক্ষর ব্যবহার করে।
def flatten_json(json):
if type(json) == dict:
for k, v in list(json.items()):
if type(v) == dict:
flatten_json(v)
json.pop(k)
for k2, v2 in v.items():
json[k+"."+k2] = v2
উদাহরণ:
d = {'a': {'b': 'c'}}
flatten_json(d)
print(d)
unflatten_json(d)
print(d)
আউটপুট:
{'a.b': 'c'}
{'a': {'b': 'c'}}
আমি এখানে ম্যাচিং unflatten_json
ফাংশন সহ এই কোডটি প্রকাশ করেছি ।
আপনি যদি নেস্টেড ডিকশনারিটি ফ্ল্যাট করতে চান এবং সমস্ত অনন্য কী তালিকা চান তবে সমাধানটি এখানে দেওয়া হল:
def flat_dict_return_unique_key(data, unique_keys=set()):
if isinstance(data, dict):
[unique_keys.add(i) for i in data.keys()]
for each_v in data.values():
if isinstance(each_v, dict):
flat_dict_return_unique_key(each_v, unique_keys)
return list(set(unique_keys))
def flatten(unflattened_dict, separator='_'):
flattened_dict = {}
for k, v in unflattened_dict.items():
if isinstance(v, dict):
sub_flattened_dict = flatten(v, separator)
for k2, v2 in sub_flattened_dict.items():
flattened_dict[k + separator + k2] = v2
else:
flattened_dict[k] = v
return flattened_dict
def flatten_nested_dict(_dict, _str=''):
'''
recursive function to flatten a nested dictionary json
'''
ret_dict = {}
for k, v in _dict.items():
if isinstance(v, dict):
ret_dict.update(flatten_nested_dict(v, _str = '_'.join([_str, k]).strip('_')))
elif isinstance(v, list):
for index, item in enumerate(v):
if isinstance(item, dict):
ret_dict.update(flatten_nested_dict(item, _str= '_'.join([_str, k, str(index)]).strip('_')))
else:
ret_dict['_'.join([_str, k, str(index)]).strip('_')] = item
else:
ret_dict['_'.join([_str, k]).strip('_')] = v
return ret_dict
আমি কীভাবে স্বয়ংক্রিয়ভাবে চাবিগুলি ফ্ল্যাট করতে ইউজারডিক্টের সাবক্লাসের কথা ভাবছিলাম।
class FlatDict(UserDict):
def __init__(self, *args, separator='.', **kwargs):
self.separator = separator
super().__init__(*args, **kwargs)
def __setitem__(self, key, value):
if isinstance(value, dict):
for k1, v1 in FlatDict(value, separator=self.separator).items():
super().__setitem__(f"{key}{self.separator}{k1}", v1)
else:
super().__setitem__(key, value)
ঃ উড়ে যাওয়ার উপায়ে কীগুলি যুক্ত করা যায় বা অবাক না করে স্ট্যান্ডার্ড ডিক ইনস্ট্যান্সেশন ব্যবহার করা যায় সেগুলি:
>>> fd = FlatDict(
... {
... 'person': {
... 'sexe': 'male',
... 'name': {
... 'first': 'jacques',
... 'last': 'dupond'
... }
... }
... }
... )
>>> fd
{'person.sexe': 'male', 'person.name.first': 'jacques', 'person.name.last': 'dupond'}
>>> fd['person'] = {'name': {'nickname': 'Bob'}}
>>> fd
{'person.sexe': 'male', 'person.name.first': 'jacques', 'person.name.last': 'dupond', 'person.name.nickname': 'Bob'}
>>> fd['person.name'] = {'civility': 'Dr'}
>>> fd
{'person.sexe': 'male', 'person.name.first': 'jacques', 'person.name.last': 'dupond', 'person.name.nickname': 'Bob', 'person.name.civility': 'Dr'}
জেনারেটর ব্যবহার:
def flat_dic_helper(prepand,d):
if len(prepand) > 0:
prepand = prepand + "_"
for k in d:
i=d[k]
if type(i).__name__=='dict':
r = flat_dic_helper(prepand+k,i)
for j in r:
yield j
else:
yield (prepand+k,i)
def flat_dic(d): return dict(flat_dic_helper("",d))
d={'a': 1, 'c': {'a': 2, 'b': {'x': 5, 'y' : 10}}, 'd': [1, 2, 3]}
print(flat_dic(d))
>> {'a': 1, 'c_a': 2, 'c_b_x': 5, 'd': [1, 2, 3], 'c_b_y': 10}
type(i).__name__=='dict'
এর সাথে type(i) is dict
বা সম্ভবত আরও ভাল isinstance(d, dict)
(বা Mapping
/ MutableMapping
) প্রতিস্থাপন করা যেতে পারে ।
ডেকে.পোপিটেম () ব্যবহার করে সরাসরি নেস্টেড-তালিকার মতো পুনরাবৃত্তি:
def flatten(d):
if d == {}:
return d
else:
k,v = d.popitem()
if (dict != type(v)):
return {k:v, **flatten(d)}
else:
flat_kv = flatten(v)
for k1 in list(flat_kv.keys()):
flat_kv[k + '_' + k1] = flat_kv[k1]
del flat_kv[k1]
return {**flat_kv, **flatten(d)}
ওপি যা বলেছিল ঠিক তাই নয়, প্রচুর লোকেরা এখানে আসছেন রিয়েল-ওয়ার্ল্ড নেস্টেড জেএসওএন ডেটা সমতল করার উপায়গুলির সন্ধানের জন্য যা কী-ভ্যালু জেসন অবজেক্টস এবং অ্যারে এবং জেসন অবজেক্টগুলিতে অ্যারে ইত্যাদিতে থাকতে পারে। JSON টিপলসকে অন্তর্ভুক্ত করে না, সুতরাং আমাদের সেগুলি নিয়ে হতাশার দরকার নেই।
আমি তালিকায়-অন্তর্ভুক্তি একটি বাস্তবায়ন পাওয়া @roneo মন্তব্য করার জন্য উত্তর @Imran পোস্ট করেছে :
https://github.com/ScriptSmith/socialreaper/blob/master/socialreaper/tools.py#L8
import collections
def flatten(dictionary, parent_key=False, separator='.'):
"""
Turn a nested dictionary into a flattened dictionary
:param dictionary: The dictionary to flatten
:param parent_key: The string to prepend to dictionary's keys
:param separator: The string used to separate flattened keys
:return: A flattened dictionary
"""
items = []
for key, value in dictionary.items():
new_key = str(parent_key) + separator + key if parent_key else key
if isinstance(value, collections.MutableMapping):
items.extend(flatten(value, new_key, separator).items())
elif isinstance(value, list):
for k, v in enumerate(value):
items.extend(flatten({str(k): v}, new_key).items())
else:
items.append((new_key, value))
return dict(items)
এটা পরীক্ষা করো:
flatten({'a': 1, 'c': {'a': 2, 'b': {'x': 5, 'y' : 10}}, 'd': [1, 2, 3] })
>> {'a': 1, 'c.a': 2, 'c.b.x': 5, 'c.b.y': 10, 'd.0': 1, 'd.1': 2, 'd.2': 3}
আমার যে কাজটি করা দরকার তা অন্ড করে: আমি এগুলিতে যে কোনও জটিল জসন নিক্ষেপ করি এবং এটি আমার জন্য এটি ফ্ল্যাট করে দেয়।
Https://github.com/ScriptSmith এ সমস্ত ক্রেডিট ।
এই সঠিক ধরণের জিনিসটি মোকাবিলার জন্য আমি সম্প্রতি চেরিপিকার নামে একটি প্যাকেজ লিখেছিলাম যেহেতু আমাকে প্রায়শই এটি করতে হয়েছিল!
আমি মনে করি যে নিম্নলিখিত কোডটি আপনাকে ঠিক তার পরে যা দেবে:
from cherrypicker import CherryPicker
dct = {
'a': 1,
'c': {
'a': 2,
'b': {
'x': 5,
'y' : 10
}
},
'd': [1, 2, 3]
}
picker = CherryPicker(dct)
picker.flatten().get()
আপনি এই সাথে প্যাকেজটি ইনস্টল করতে পারেন:
pip install cherrypicker
... এবং আরও https://cherrypicker.readthedocs.io এ আরও দস্তাবেজ এবং গাইডেন্স রয়েছে ।
অন্যান্য পদ্ধতিগুলি দ্রুত হতে পারে তবে এই প্যাকেজের অগ্রাধিকার হ'ল এই জাতীয় কাজগুলি সহজ করে তোলা । আপনার কাছে যদিও সমতল করার জন্য সামগ্রীর একটি বৃহত তালিকা রয়েছে, আপনি চেরিপিকারকে জিনিসগুলি গতি বাড়ানোর জন্য সমান্তরাল প্রক্রিয়াকরণ ব্যবহার করতেও বলতে পারেন।
আমি সর্বদা এর dict
মাধ্যমে অ্যাক্সেস অবজেক্টগুলিকে পছন্দ করি .items()
, তাই চ্যাপ্টা বিভাজনের জন্য আমি নীচের পুনরাবৃত্ত জেনারেটরটি ব্যবহার করি flat_items(d)
। আপনি যদি dict
আবার থাকতে চান তবে কেবল এটির মতো মোড়ানো করুন:flat = dict(flat_items(d))
def flat_items(d, key_separator='.'):
"""
Flattens the dictionary containing other dictionaries like here: /programming/6027558/flatten-nested-python-dictionaries-compressing-keys
>>> example = {'a': 1, 'c': {'a': 2, 'b': {'x': 5, 'y' : 10}}, 'd': [1, 2, 3]}
>>> flat = dict(flat_items(example, key_separator='_'))
>>> assert flat['c_b_y'] == 10
"""
for k, v in d.items():
if type(v) is dict:
for k1, v1 in flat_items(v, key_separator=key_separator):
yield key_separator.join((k, k1)), v1
else:
yield k, v
এই ফ্ল্যাটেন নেস্টেড ডিকশনারিগুলির ভিন্নতা, ম্যাক্সলেভেল এবং কাস্টম রিডুসার দিয়ে কী সংকোচন করছে ।
def flatten(d, max_level=None, reducer='tuple'):
if reducer == 'tuple':
reducer_seed = tuple()
reducer_func = lambda x, y: (*x, y)
else:
raise ValueError(f'Unknown reducer: {reducer}')
def impl(d, pref, level):
return reduce(
lambda new_d, kv:
(max_level is None or level < max_level)
and isinstance(kv[1], dict)
and {**new_d, **impl(kv[1], reducer_func(pref, kv[0]), level + 1)}
or {**new_d, reducer_func(pref, kv[0]): kv[1]},
d.items(),
{}
)
return impl(d, reducer_seed, 0)
আপনি যদি পুনরাবৃত্ত ফাংশনগুলিতে কিছু মনে করেন না, তবে এখানে একটি সমাধান রয়েছে। আমিও স্বাধীনতা নিয়েছি একটি অন্তর্ভুক্ত করা বর্জনআপনি বজায় রাখতে ইচ্ছুক এক বা একাধিক মান থাকতে পারে এমন ক্ষেত্রেও প্যারামিটার ।
কোড:
def flatten_dict(dictionary, exclude = [], delimiter ='_'):
flat_dict = dict()
for key, value in dictionary.items():
if isinstance(value, dict) and key not in exclude:
flatten_value_dict = flatten_dict(value, exclude, delimiter)
for k, v in flatten_value_dict.items():
flat_dict[f"{key}{delimiter}{k}"] = v
else:
flat_dict[key] = value
return flat_dict
ব্যবহার:
d = {'a':1, 'b':[1, 2], 'c':3, 'd':{'a':4, 'b':{'a':7, 'b':8}, 'c':6}, 'e':{'a':1,'b':2}}
flat_d = flatten_dict(dictionary=d, exclude=['e'], delimiter='.')
print(flat_d)
আউটপুট:
{'a': 1, 'b': [1, 2], 'c': 3, 'd.a': 4, 'd.b.a': 7, 'd.b.b': 8, 'd.c': 6, 'e': {'a': 1, 'b': 2}}
আমি এই পৃষ্ঠায় কয়েকটি সমাধানের চেষ্টা করেছি - যদিও সব কিছু নয় - তবে আমি চেষ্টা করেছি তারা ডিকের নেস্টেড তালিকা পরিচালনা করতে ব্যর্থ হয়েছিল।
এই মত একটি ডিক বিবেচনা করুন:
d = {
'owner': {
'name': {'first_name': 'Steven', 'last_name': 'Smith'},
'lottery_nums': [1, 2, 3, 'four', '11', None],
'address': {},
'tuple': (1, 2, 'three'),
'tuple_with_dict': (1, 2, 'three', {'is_valid': False}),
'set': {1, 2, 3, 4, 'five'},
'children': [
{'name': {'first_name': 'Jessica',
'last_name': 'Smith', },
'children': []
},
{'name': {'first_name': 'George',
'last_name': 'Smith'},
'children': []
}
]
}
}
এখানে আমার অস্থায়ী সমাধান:
def flatten_dict(input_node: dict, key_: str = '', output_dict: dict = {}):
if isinstance(input_node, dict):
for key, val in input_node.items():
new_key = f"{key_}.{key}" if key_ else f"{key}"
flatten_dict(val, new_key, output_dict)
elif isinstance(input_node, list):
for idx, item in enumerate(input_node):
flatten_dict(item, f"{key_}.{idx}", output_dict)
else:
output_dict[key_] = input_node
return output_dict
যা উত্পাদন করে:
{
owner.name.first_name: Steven,
owner.name.last_name: Smith,
owner.lottery_nums.0: 1,
owner.lottery_nums.1: 2,
owner.lottery_nums.2: 3,
owner.lottery_nums.3: four,
owner.lottery_nums.4: 11,
owner.lottery_nums.5: None,
owner.tuple: (1, 2, 'three'),
owner.tuple_with_dict: (1, 2, 'three', {'is_valid': False}),
owner.set: {1, 2, 3, 4, 'five'},
owner.children.0.name.first_name: Jessica,
owner.children.0.name.last_name: Smith,
owner.children.1.name.first_name: George,
owner.children.1.name.last_name: Smith,
}
একটি অস্থায়ী সমাধান এবং এটি নিখুঁত নয়।
বিঃদ্রঃ:
এটি address: {}
কে / ভি জুটির মতো খালি ডিক্ট রাখে না ।
এটি নেস্টেড টিউপসগুলিতে ফাঁকফোকর করে না
কেবল ব্যবহার করুন python-benedict
, এটি একটি ডিক সাবক্লাস যা একটি বৈশিষ্ট্যযুক্ত অনেকগুলি বৈশিষ্ট্য সরবরাহ করে flatten
। এটি পাইপ ব্যবহার করে ইনস্টল করা সম্ভব:pip install python-benedict
https://github.com/fabiocaccamo/python-benedict#flatten
from benedict import benedict
d = benedict(data)
f = d.flatten(separator='_')