ডিকের মানটির সাথে মিল রেখে একটি তালিকার মধ্যে ডিকের সূচকটি সন্ধান করুন


130

আমার কাছে ডিক্টসের একটি তালিকা রয়েছে:

list = [{'id':'1234','name':'Jason'},
        {'id':'2345','name':'Tom'},
        {'id':'3456','name':'Art'}]

= 'টম' নামের সাথে মিল রেখে আমি কীভাবে দক্ষতার সাথে সূচক অবস্থান [0], [1], বা [2] খুঁজে পেতে পারি?

যদি এটি একটি মাত্রিক তালিকা ছিল তবে আমি list.index () করতে পারতাম তবে আমি নিশ্চিত নই যে তালিকার মধ্যে ডিক্টের মানগুলি অনুসন্ধান করে কীভাবে এগিয়ে যেতে হবে।


6
"তালিকা" হ'ল তালিকার নির্মাণকারী, আপনি তালিকার জন্য আরও একটি নাম চয়ন করতে পারেন (এমনকি একটি উদাহরণেও)। এবং কোনও উপাদান না পাওয়া গেলে তার প্রতিক্রিয়া কী হওয়া উচিত? একটি ব্যতিক্রম বাড়াতে? ফেরত না কেউ?
টোকল্যান্ড

7
আপনার যদি { 'Jason': {'id': '1234'}, 'Tom': {'id': '1245'}, ...}

3
@ ডেলানান কারণ এটি বিপর্যয়ের একটি রেসিপি! যদি কিছু হয় তবে তা হওয়া উচিত {'1234': {'name': 'Jason'}, ...}। এটি ব্যবহারের ক্ষেত্রে সহায়তা করবে না।
ওজেফোর্ড

উত্তর:


145
tom_index = next((index for (index, d) in enumerate(lst) if d["name"] == "Tom"), None)
# 1

আপনি নাম থেকে বারবার আনতে প্রয়োজন হয়, আপনি (ক অভিধান ব্যবহার করা হচ্ছে) নামে তাদের সূচক should, এই ভাবে পেতে অপারেশন হে (1) সময় হবে। একটি ধারণা:

def build_dict(seq, key):
    return dict((d[key], dict(d, index=index)) for (index, d) in enumerate(seq))

info_by_name = build_dict(lst, key="name")
tom_info = info_by_name.get("Tom")
# {'index': 1, 'id': '2345', 'name': 'Tom'}

2
IMHO এটি পড়ার মতো নয় বা পাইথোনিক @ এমিলের উত্তর। উদ্দেশ্য প্রকৃতপক্ষে কোনও জেনারেটর তৈরি করার নয় (এবং এটির next()জন্য ব্যবহার করা আমার কাছে অদ্ভুত বলে মনে হচ্ছে), উদ্দেশ্যটি কেবল সূচকটি পাওয়া। এছাড়াও, এটি lst.index()স্টপআইটারেশন উত্থাপন করে, অন্যদিকে পাইথন পদ্ধতিটি ভ্যালুআরারের উত্থাপন করে।
বেন হোয়েট

@ বেনহয়েট: আমি স্টপআইট্রেশন ব্যতিক্রমটিও পছন্দ করি না তবে আপনি যদি পরবর্তী () এর ডিফল্ট মান পরিবর্তন করতে পারেন তবে এটি যে ব্যতিক্রম উত্থাপন করে তা স্থির হয়। পাইথোনিসিটি কিছুটা সাবজেক্টিভ তাই আমি এটিকে নিয়ে বিতর্ক করব না, সম্ভবত একটি লুপটি আরও পাইথোনিক। অন্যদিকে, কিছু লোক প্রথম () এর জন্য পরবর্তী () আলাদা করে রাখে এবং এটি অবশ্যই আরও ভাল শোনাচ্ছে: প্রথম (সূচকের (সূচক, d) ইন ...)।
টোকল্যান্ড

first()ভাল শব্দ না। আপনি সর্বদা স্টপআইটারেশন ব্যতীত / চেষ্টা করতে এবং মান বাড়িয়ে তুলতে পারেন যাতে কলারের সাথে সামঞ্জস্য থাকে। বিকল্পভাবে next()এর ডিফল্ট -1 এ সেট করুন ।
বেন হোয়েট

1
@ জিডিডাব্লু ২: এটি করার সময় আমি পেয়েছি SyntaxError: Generator expression must be parenthesized if not sole argument
এভোলিভা

2
@ ওভালিভা পরের মত প্রায় প্রথম বন্ধনী যুক্ত করুনnext((index for (index, d) in enumerate(lst) if d["name"] == "Tom"), None)
হুসিয়েনকে

45

একটি সহজ পাঠযোগ্য সংস্করণ হ'ল

def find(lst, key, value):
    for i, dic in enumerate(lst):
        if dic[key] == value:
            return i
    return -1

8
এটি সর্বাধিক পঠনযোগ্য এবং পাইথোনিক বলে মনে হচ্ছে। এটি str.find()সুন্দরভাবে আচরণের নকল করে । আপনি এটি কল করতে পারেন index()এবং এটি ValueErrorপছন্দনীয় হলে -1 ফেরার পরিবর্তে একটি উত্থাপনও করতে পারেন।
বেন হোয়েট

6
সম্মত হন - 1-তে ফিরে যখন কোনও মিল পাওয়া যায় না, আপনি সর্বদা তালিকার সর্বশেষ ডিকটি পাবেন, যা সম্ভবত আপনি চান না। কিছুই না ফেরানো ভাল এবং কলিং কোডে কোনও ম্যাচের অস্তিত্বের জন্য পরীক্ষা করুন।
শ্যাকার

9

এটি দক্ষ হবে না, কারণ এতে প্রতিটি আইটেম (O (n)) যাচাই করে আপনার তালিকায় হাঁটতে হবে। আপনি যদি দক্ষতা চান তবে আপনি ডিক্টের ডিক ব্যবহার করতে পারেন । এই প্রশ্নে এটি সন্ধানের একটি সম্ভাব্য উপায় (যদিও আপনি যদি এই ডেটা কাঠামোর সাথে লেগে থাকতে চান তবে ব্রেন্ট নিউ যে মন্তব্যগুলিতে লিখেছেন তেমন জেনারেটরটি ব্যবহার করা আরও কার্যকরী ; টোকল্যান্ডের উত্তরও দেখুন):

>>> L = [{'id':'1234','name':'Jason'},
...         {'id':'2345','name':'Tom'},
...         {'id':'3456','name':'Art'}]
>>> [i for i,_ in enumerate(L) if _['name'] == 'Tom'][0]
1

1
আপনি একটি জেনারেটর ব্যবহার করে আপনার দক্ষতা অর্জন করতে পারেন। টোকল্যান্ডের উত্তর দেখুন।
ব্রেন্ট

2
@ ব্রেন্ট নেউই: জেনারেটর এই সত্যটি পরিবর্তন করে না যে আপনাকে পুরো তালিকাটি অতিক্রম করতে হবে এবং অনুসন্ধান ও (এন) কে অ্যান্টারের দাবি হিসাবে তৈরি করা হবে ... সেই তালিকা কত দীর্ঘ রয়েছে তার উপর নির্ভর করে জেনারেটর বনাম ব্যবহারের মধ্যে পার্থক্য লুপের জন্য বা যা কিছু অবহেলা হতে পারে, ডিক বনাম ব্যবহারের মধ্যে পার্থক্য সহ একটি তালিকা ব্যবহার নাও করতে পারে
ডার্ক

@ ব্রেন্ট: আপনি ঠিক বলেছেন, তবে অনুসন্ধানের আইটেমটি তালিকার শেষে থাকলে এটি কোনও অভিধানে একটি ও (1) অনুসন্ধানকে পরাজিত করতে পারে?
এেটর

1
@ ডির্ক পরের () জেনারেটরের সাথে কলটি কোনও মিল পাওয়া গেলে থামায়, সুতরাং এটি পুরো তালিকাটি অতিক্রম করতে হবে না।
ব্রেন্ট

@ এটার আপনি একটি সুস্পষ্ট বক্তব্য রাখেন। আমি যখন কোনও ম্যাচ পাওয়া যায় তখন থামতে সক্ষম হচ্ছিলাম।
ব্রেন্ট

2

এখানে একটি ফাংশন রয়েছে যা অভিধানের সূচক অবস্থানটি উপস্থিত থাকলে এটি সন্ধান করে।

dicts = [{'id':'1234','name':'Jason'},
         {'id':'2345','name':'Tom'},
         {'id':'3456','name':'Art'}]

def find_index(dicts, key, value):
    class Null: pass
    for i, d in enumerate(dicts):
        if d.get(key, Null) == value:
            return i
    else:
        raise ValueError('no dict with the key and value combination found')

print find_index(dicts, 'name', 'Tom')
# 1
find_index(dicts, 'name', 'Ensnare')
# ValueError: no dict with the key and value combination found

2

ফিল্টার / সূচী কম্বো ব্যবহার করা সবচেয়ে যুক্তিযুক্ত বলে মনে হচ্ছে:

names=[{}, {'name': 'Tom'},{'name': 'Tony'}]
names.index(filter(lambda n: n.get('name') == 'Tom', names)[0])
1

এবং যদি আপনি ভাবেন যে একাধিক ম্যাচ হতে পারে:

[names.index(n) for item in filter(lambda n: n.get('name') == 'Tom', names)]
[1]

2

@ ফাহামের দেওয়া উত্তরটি একটি দুর্দান্ত এক-লাইনার, তবে এটি মূল্য সহ অভিধানটিতে সূচকটি ফিরিয়ে দেয় না। পরিবর্তে এটি অভিধান নিজেই ফেরত দেয়। এখানে যাওয়ার একটি সহজ উপায়: একের বেশি হলে সূচকের একটি বা একাধিক, বা যদি না থাকে তবে খালি তালিকা:

list = [{'id':'1234','name':'Jason'},
        {'id':'2345','name':'Tom'},
        {'id':'3456','name':'Art'}]

[i for i, d in enumerate(list) if 'Tom' in d.values()]

আউটপুট:

>>> [1]

আমি এই পদ্ধতির সম্পর্কে যা পছন্দ করি তা হ'ল একটি সাধারণ সম্পাদনা দ্বারা আপনি উভয় সূচী এবং অভিধান উভয়ের তালিকা হিসাবে টিপলস পেতে পারেন। এই উত্তরগুলি সমাধান করার জন্য আমার যে সমস্যাটি প্রয়োজন তা হ'ল। নিম্নলিখিতটিতে, আমি এটি কীভাবে কাজ করে তা দেখানোর জন্য একটি আলাদা অভিধানে একটি সদৃশ মান যুক্ত করেছি:

list = [{'id':'1234','name':'Jason'},
        {'id':'2345','name':'Tom'},
        {'id':'3456','name':'Art'},
        {'id':'4567','name':'Tom'}]

[(i, d) for i, d in enumerate(list) if 'Tom' in d.values()]

আউটপুট:

>>> [(1, {'id': '2345', 'name': 'Tom'}), (3, {'id': '4567', 'name': 'Tom'})]

এই সমাধানটিতে তাদের কোনও মানগুলিতে 'টম' যুক্ত সমস্ত অভিধান খুঁজে পাওয়া যায়।


1

এক রৈখিক!?

elm = ([i for i in mylist if i['name'] == 'Tom'] or [None])[0]

0

প্রদত্ত পুনরাবৃত্তির জন্য, more_itertools.locateএমন আইটেমের অবস্থানের ফলন দেয় যা কোনও প্রাকটিকাকে সন্তুষ্ট করে।

import more_itertools as mit


iterable = [
    {"id": "1234", "name": "Jason"},
    {"id": "2345", "name": "Tom"},
    {"id": "3456", "name": "Art"}
]

list(mit.locate(iterable, pred=lambda d: d["name"] == "Tom"))
# [1]

more_itertoolsএকটি তৃতীয় পক্ষের লাইব্রেরি যা অন্যান্য দরকারী সরঞ্জামগুলির মধ্যে ইটারটুল রেসিপি প্রয়োগ করে।


আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.