ย้อนกลับ / กลับการจับคู่พจนานุกรม


คำตอบ:


923

สำหรับ Python 2.7.x

inv_map = {v: k for k, v in my_map.iteritems()}

สำหรับ Python 3+:

inv_map = {v: k for k, v in my_map.items()}

4
ในเวอร์ชัน Python 2.7.x ล่าสุดmy_map.items()ทำงานได้ดี
Valentin

29
สิ่งนี้จะใช้งานได้ยกเว้นว่ามันจะไม่ทำงานหากไม่มีความสามัคคีในค่า ในกรณีนี้คุณจะหลวมบางรายการ
gabuzo


2
ใช่เป็นรายละเอียดการใช้งาน The order-preserving aspect of this new implementation is considered an implementation detail and should not be relied upon. ไม่มีการรับประกันว่าจะอยู่ทางนั้นจึงไม่เขียนโค้ดอาศัยไม่เป็นมีพฤติกรรมเช่นเดียวกับDict OrderedDict
Mattias

9
@Mattias สิ่งนี้เป็นจริงสำหรับ Python 3.6 สำหรับรุ่น 3.7 เพื่อรักษาอย่างเป็นทางการ: mail.python.org/pipermail/python-dev/2017-December/151283.html BDFL พูดอย่างนั้น
interDist

174

สมมติว่าค่าใน dict นั้นไม่ซ้ำกัน:

dict((v, k) for k, v in my_map.iteritems())

22
ค่าจะต้อง hashable เกินไป
John La Rooy

30
@ Buttons840: หากค่านั้นไม่ซ้ำกันจะไม่มีการกลับตัวของพจนานุกรมที่ไม่ซ้ำกันหรือด้วยคำอื่น ๆ การสลับกลับไม่เข้าท่า
Wrzlprmft

2
@ Buttons840 เฉพาะคีย์สุดท้ายเท่านั้นที่จะปรากฏสำหรับค่า อาจไม่มีการรับประกันเกี่ยวกับคำสั่งที่iteritems()จะส่งออกดังนั้นจึงอาจสันนิษฐานได้ว่าจะมีการกำหนดคีย์ที่กำหนดเองให้กับค่าที่ไม่ซ้ำกันในลักษณะที่จะทำซ้ำได้อย่างชัดเจนภายใต้เงื่อนไขบางประการ แต่ไม่มีโดยทั่วไป
Evgeni Sergeev

2
โปรดทราบว่าใน Python 3 ไม่มีiteritems()วิธีการอีกต่อไปและวิธีนี้จะไม่ทำงาน ใช้ที่items()นั่นแทนดังที่แสดงในคำตอบที่ยอมรับ dictนอกจากนี้ยังมีความเข้าใจในพจนานุกรมจะทำให้สวยกว่านี้โทร
Mark Amery

5
@Wrzlprmft มีคำจำกัดความตามธรรมชาติสำหรับผกผันในกรณีที่มีค่าไม่ซ้ำกัน ค่าทุกค่าจะถูกแมปกับชุดของคีย์ที่นำไปสู่
Leo

135

หากค่าในmy_mapนั้นไม่ซ้ำกัน:

inv_map = {}
for k, v in my_map.iteritems():
    inv_map[v] = inv_map.get(v, [])
    inv_map[v].append(k)

56
... หรือเพียงแค่ inv_map.setdefault (v, []). ผนวก (k) ฉันเคยเป็นแฟนบอยผิดนัด แต่แล้วฉันก็เมาไปหลายครั้งเกินไปและสรุปว่าจริง ๆ แล้วดีกว่าโดยปริยาย
alsuren

คำตอบนี้ไม่ถูกต้องสำหรับหลายแผนที่ผนวกที่นี่ไม่มีประโยชน์เพราะค่าถูกรีเซ็ตเป็นรายการที่ว่างเปล่าในแต่ละครั้งควรใช้ set_default
Yaroslav Bulatov

1
@YaroslavBulatov ไม่รหัสที่แสดงในที่นี้จะไม่เสียหาย - inv_map.get(v, [])ส่งคืนรายการที่เพิ่มไว้แล้วหากมีอยู่ดังนั้นการมอบหมายไม่ได้รีเซ็ตเป็นรายการว่าง setdefaultจะยังคงสวยกว่านี้
Mark Amery

10
ชุดจะทำให้เข้าใจมากขึ้นที่นี่ กุญแจเหล่านี้ (อาจ) แฮชได้และไม่มีคำสั่ง inv_map.setdefault(v, set()).add(k).
Artyer

1
ใน python3 ใช้แทนmy_map.items() my_map.iteritems()
apitsch

42

ในการทำเช่นนี้ในขณะที่ยังคงรักษาประเภทของการแมปของคุณไว้ (สมมติว่ามันเป็นคลาสย่อยdictหรือdict):

def inverse_mapping(f):
    return f.__class__(map(reversed, f.items()))

4
อาจจะฉลาด แต่ก็ไม่ทำงานเมื่อมีมากกว่าหนึ่งคีย์ที่มีค่าเหมือนกันในพจนานุกรมต้นฉบับ
Rafael_Espericueta

1
@Rafael_Espericueta นั่นเป็นเรื่องจริงสำหรับคำตอบใด ๆ ที่เป็นไปได้สำหรับคำถามนี้เนื่องจากแผนที่ที่มีค่าซ้ำไม่สามารถย้อนกลับได้
Mark Amery

2
@ Mark_Amery มันสามารถย้อนกลับได้มากกว่าโดยทั่วไปในแง่หนึ่ง ตัวอย่างเช่น: D = {1: [1, 2], 2: [2, 3], 3: [1]}, Dinv = {1: [1, 3], 2: [1, 2], 3: [2]} D เป็นพจนานุกรมตัวอย่างเช่น {parent: children} ในขณะที่ Dinv เป็นพจนานุกรม {child: parent}
Rafael_Espericueta

36

ลองสิ่งนี้:

inv_map = dict(zip(my_map.values(), my_map.keys()))

(โปรดทราบว่าเอกสาร Python ในมุมมองพจนานุกรมรับประกันอย่างชัดเจน.keys()และ.values()มีองค์ประกอบในลำดับเดียวกันซึ่งช่วยให้วิธีการด้านบนทำงานได้)

อีกวิธีหนึ่งคือ:

inv_map = dict((my_map[k], k) for k in my_map)

หรือใช้ความเข้าใจพจน์ของ python 3.0

inv_map = {my_map[k] : k for k in my_map}

1
ขอให้สังเกตว่าจะใช้งานได้เฉพาะในกรณีที่คีย์ไม่ซ้ำกัน (ซึ่งแทบจะไม่เคยเกิดขึ้นหากคุณต้องการสลับกลับ)
ghent

ตามpython.org/dev/peps/pep-0274 dict comprehensions มีอยู่ใน 2.7+ ด้วย
Kawu

24

อีกวิธีที่ทำงานได้มากขึ้น:

my_map = { 'a': 1, 'b':2 }
dict(map(reversed, my_map.items()))

3
ขอบคุณสำหรับการโพสต์ ฉันไม่แน่ใจว่าสิ่งนี้ดีกว่าหรือไม่ - เพื่ออ้างถึง Guido Van Rossum ใน PEP 279: " filterและmapควรตายและถูกนำไปรวมไว้ในรายการความเข้าใจ
Brian M. Hunt

2
ใช่นั่นคือจุดที่ยุติธรรมไบรอัน ฉันแค่เพิ่มมันเป็นจุดสนทนา วิธีอ่านความเข้าใจพจน์สามารถอ่านได้มากขึ้นสำหรับส่วนใหญ่ฉันคิด (และน่าจะเร็วกว่าด้วยฉันเดา)
เบรนแดนแมกไกวร์

3
อาจจะอ่านได้น้อยกว่าคนอื่น ๆ แต่วิธีนี้มีประโยชน์ที่จะสามารถสลับdictกับการทำแผนที่ประเภทอื่น ๆ เช่นcollections.OrderedDictหรือcollections.defaultdict
Will S

10

สิ่งนี้จะขยายออกไปตามคำตอบของโรเบิร์ตซึ่งนำไปใช้กับเมื่อค่าใน dict นั้นไม่ซ้ำกัน

class ReversibleDict(dict):

    def reversed(self):
        """
        Return a reversed dict, with common values in the original dict
        grouped into a list in the returned dict.

        Example:
        >>> d = ReversibleDict({'a': 3, 'c': 2, 'b': 2, 'e': 3, 'd': 1, 'f': 2})
        >>> d.reversed()
        {1: ['d'], 2: ['c', 'b', 'f'], 3: ['a', 'e']}
        """

        revdict = {}
        for k, v in self.iteritems():
            revdict.setdefault(v, []).append(k)
        return revdict

การใช้งานมีข้อ จำกัด ในการที่คุณไม่สามารถใช้reversedสองครั้งและได้รับต้นฉบับ มันไม่สมมาตรเช่นนี้ ผ่านการทดสอบกับ Python 2.6 นี่คือกรณีการใช้งานของวิธีการที่ฉันใช้ในการพิมพ์ผลลัพธ์ dict

ถ้าคุณต้องการใช้setกว่าlistและมีการใช้งานอยู่สามารถเรียงลำดับที่นี้ทำให้รู้สึกแทนการใช้setdefault(v, []).append(k)setdefault(v, set()).add(k)


นี่จะเป็นสถานที่ที่ดีในการใช้ชุดแทนรายการเช่นrevdict.setdefault(v, set()).add(k)
mueslo

แน่นอน แต่ที่ exacty setของเหตุผลที่มันเป็นเหตุผลที่ดีที่จะใช้ เป็นประเภทที่แท้จริงที่ใช้ที่นี่ จะทำอย่างไรถ้าฉันต้องการหากุญแจทั้งหมดที่มีค่า1หรือ2ไม่ จากนั้นฉันก็ทำได้d.keys() - inv_d[1] - inv_d[2](ใน Python 3)
mueslo

9

นอกจากนี้เรายังสามารถย้อนกลับพจนานุกรมด้วยคีย์ซ้ำโดยใช้defaultdict:

from collections import Counter, defaultdict

def invert_dict(d):
    d_inv = defaultdict(list)
    for k, v in d.items():
        d_inv[v].append(k)
    return d_inv

text = 'aaa bbb ccc ddd aaa bbb ccc aaa' 
c = Counter(text.split()) # Counter({'aaa': 3, 'bbb': 2, 'ccc': 2, 'ddd': 1})
dict(invert_dict(c)) # {1: ['ddd'], 2: ['bbb', 'ccc'], 3: ['aaa']}  

ดูที่นี่ :

dict.setdefault()เทคนิคนี้จะง่ายและเร็วกว่าเทคนิคการใช้เทียบเท่า


6

ตัวอย่างเช่นคุณมีพจนานุกรมต่อไปนี้:

dict = {'a': 'fire', 'b': 'ice', 'c': 'fire', 'd': 'water'}

และคุณต้องการที่จะได้มันในรูปแบบฤ:ษี:

inverted_dict = {'fire': ['a', 'c'], 'ice': ['b'], 'water': ['d']}

โซลูชั่นแรก สำหรับการย้อนกลับคู่คีย์ - ค่าในพจนานุกรมของคุณให้ใช้forวิธี -loop:

# Use this code to invert dictionaries that have non-unique values

inverted_dict = dict()
for key, value in dict.items():
    inverted_dict.setdefault(value, list()).append(key)

โซลูชั่นที่สอง ใช้แนวทางความเข้าใจในพจนานุกรมสำหรับการกลับรายการ:

# Use this code to invert dictionaries that have unique values

inverted_dict = {value: key for key, value in dict.items()}

โซลูชั่นที่สาม ใช้การย้อนกลับวิธีการกลับรายการ (อาศัยโซลูชันที่สอง):

# Use this code to invert dictionaries that have lists of values

dict = {value: key for key in inverted_dict for value in my_map[key]}

4
dictสงวนไว้และไม่ควรใช้สำหรับชื่อตัวแปร
crypdick

2
ลืมบอกเราว่าmy_mapคืออะไร
crypdick

dictio()? คุณหมายถึงdict()อะไร
Georgy

5

การรวมกันของรายการและความเข้าใจในพจนานุกรม สามารถจัดการกับกุญแจที่ซ้ำกัน

{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}

1
เช่นstackoverflow.com/a/41861007/1709587นี่เป็นวิธีการแก้ปัญหา O (n²) สำหรับปัญหาที่แก้ไขได้อย่างง่ายดายใน O (n) ด้วยโค้ดเพิ่มเติมสองสามบรรทัด
Mark Amery

2

หากค่าไม่ซ้ำกันและคุณเป็นคนง่าย ๆ เล็กน้อย:

inv_map = dict(
    (v, [k for (k, xx) in filter(lambda (key, value): value == v, my_map.items())]) 
    for v in set(my_map.values())
)

โดยเฉพาะอย่างยิ่งสำหรับ dict ขนาดใหญ่โปรดทราบว่าวิธีนี้มีประสิทธิภาพน้อยกว่าคำตอบที่Python ย้อนกลับ / กลับการแม็พเนื่องจากมันวนซ้ำitems()หลายครั้ง


7
นี่เป็นเพียงอ่านไม่ได้ธรรมดาและเป็นตัวอย่างที่ดีของวิธีการเขียนรหัสที่สามารถบำรุงรักษาได้ ฉันจะไม่-1เพราะมันยังคงตอบคำถามเพียงความเห็นของฉัน
Russ Bradberry

1

นอกเหนือจากฟังก์ชั่นอื่น ๆ ที่แนะนำข้างต้นหากคุณชอบ lambdas:

invert = lambda mydict: {v:k for k, v in mydict.items()}

หรือคุณสามารถทำได้ด้วยวิธีนี้เช่นกัน:

invert = lambda mydict: dict( zip(mydict.values(), mydict.keys()) )

2
-1; สิ่งที่คุณทำทั้งหมดนั้นจะได้รับคำตอบอื่น ๆ จากหน้านี้และใส่ลงในแลมบ์ดา นอกจากนี้การกำหนดแลมบ์ดาให้กับตัวแปรถือเป็นการละเมิดPEP 8
Mark Amery

1

ฉันคิดว่าวิธีที่ดีที่สุดในการทำเช่นนี้คือการกำหนดชั้นเรียน นี่คือการดำเนินการของ "พจนานุกรมสมมาตร":

class SymDict:
    def __init__(self):
        self.aToB = {}
        self.bToA = {}

    def assocAB(self, a, b):
        # Stores and returns a tuple (a,b) of overwritten bindings
        currB = None
        if a in self.aToB: currB = self.bToA[a]
        currA = None
        if b in self.bToA: currA = self.aToB[b]

        self.aToB[a] = b
        self.bToA[b] = a
        return (currA, currB)

    def lookupA(self, a):
        if a in self.aToB:
            return self.aToB[a]
        return None

    def lookupB(self, b):
        if b in self.bToA:
            return self.bToA[b]
        return None

วิธีการลบและการทำซ้ำนั้นง่ายพอที่จะนำไปใช้หากต้องการ

การนำไปใช้นี้มีประสิทธิภาพมากกว่าการสลับทั้งพจนานุกรม (ซึ่งน่าจะเป็นคำตอบที่ได้รับความนิยมมากที่สุดในหน้านี้) ไม่ต้องพูดถึงคุณสามารถเพิ่มหรือลบค่าออกจาก SymDict ของคุณได้มากเท่าที่คุณต้องการและ Inverse-dictionary ของคุณจะยังคงใช้งานได้อยู่เสมอ - สิ่งนี้ไม่เป็นความจริงถ้าคุณย้อนกลับทั้งพจนานุกรมหนึ่งครั้ง


ฉันชอบความคิดนี้แม้ว่าจะเป็นการดีที่จะทราบว่ามันทำการปิดหน่วยความจำเพิ่มเติมเพื่อให้ได้การคำนวณที่ดีขึ้น สื่อที่มีความสุขกว่าอาจจะแคชหรือคำนวณกระจกอย่างเกียจคร้าน นอกจากนี้ยังเป็นที่น่าสังเกตว่ามันสามารถทำให้เกิดความน่าสนใจทาง syntactically ขึ้นเช่นมุมมองพจนานุกรมและตัวดำเนินการที่กำหนดเอง
Brian M. Hunt

@ BrianM.Hunt มันซื้อขายหน่วยความจำ แต่ไม่มาก คุณเก็บพอยน์เตอร์สองชุดไว้ที่แต่ละวัตถุเท่านั้น หากวัตถุของคุณใหญ่กว่าจำนวนเต็มเดียวสิ่งนี้จะไม่สร้างความแตกต่างมากนัก ถ้าคุณมีโต๊ะขนาดใหญ่ของวัตถุเล็ก ๆ บนมืออื่น ๆ ที่คุณอาจจะต้องพิจารณาข้อเสนอแนะที่ ...
NcAdams

และฉันเห็นด้วยมีมากขึ้นที่จะต้องทำที่นี่ - ฉันอาจเนื้อออกเป็นประเภทข้อมูลการทำงานอย่างเต็มที่ในภายหลัง
NcAdams

2
"การใช้งานนี้มีประสิทธิภาพมากกว่าการสลับทั้งพจนานุกรม" - เอ่อทำไม? ฉันไม่เห็นว่าวิธีการนี้มีเหตุผลที่เป็นไปได้ที่จะได้รับประโยชน์ด้านประสิทธิภาพอย่างมาก คุณยังมีพจนานุกรมสองเล่มด้วยวิธีนี้ หากมีสิ่งใดฉันคาดหวังว่าสิ่งนี้จะช้ากว่าพูด inverting the dict ด้วยความเข้าใจเพราะถ้าคุณ invert the the Dict Python สามารถรู้ล่วงหน้าได้ว่ามีกี่ buckets ที่จะจัดสรรในโครงสร้างข้อมูล C พื้นฐานและสร้างผกผันผกผัน โดยไม่เคยโทรdictresizeแต่วิธีนี้ปฏิเสธ Python ที่เป็นไปได้
Mark Amery

1

วิธีนี้จะจัดการกับค่าที่ไม่ซ้ำกันและรักษาลักษณะส่วนใหญ่ของกรณีที่ไม่ซ้ำกัน

inv_map = {v:[k for k in my_map if my_map[k] == v] for v in my_map.itervalues()}

สำหรับงูหลาม 3.x แทนที่ด้วยitervaluesvalues


3
วิธีแก้ปัญหานี้ค่อนข้างสง่างามเหมือนเป็นสายการบินเดียว อย่างไรก็ตามมันมีความซับซ้อนใน O (n2) ซึ่งหมายความว่ามันควรจะใช้ได้หลายสิบองค์ประกอบ แต่มันจะช้าเกินไปสำหรับการใช้งานจริงถ้าคุณมีองค์ประกอบหลายร้อยหลายพันในพจนานุกรมเริ่มต้นของคุณ การแก้ปัญหาที่อิงจาก dict เริ่มต้นนั้นเร็วกว่าวิธีนี้
gabuzo

Gabuzo ค่อนข้างถูก รุ่นนี้ชัดเจนกว่าเนื้อหาบางส่วน แต่ไม่เหมาะกับข้อมูลขนาดใหญ่
Ersatz Kwisatz

0

ฟังก์ชั่นเป็นสมมาตรสำหรับค่าของรายการประเภท; สิ่งอันดับจะถูก coverted กับรายการเมื่อดำเนินการ reverse_dict (reverse_dict (พจนานุกรม))

def reverse_dict(dictionary):
    reverse_dict = {}
    for key, value in dictionary.iteritems():
        if not isinstance(value, (list, tuple)):
            value = [value]
        for val in value:
            reverse_dict[val] = reverse_dict.get(val, [])
            reverse_dict[val].append(key)
    for key, value in reverse_dict.iteritems():
        if len(value) == 1:
            reverse_dict[key] = value[0]
    return reverse_dict

0

เนื่องจากพจนานุกรมต้องการคีย์ที่ไม่ซ้ำกันหนึ่งรายการในพจนานุกรมซึ่งแตกต่างจากค่าเราจึงต้องผนวกค่าที่กลับรายการในรายการการเรียงลำดับเพื่อรวมไว้ในคีย์เฉพาะใหม่

def r_maping(dictionary):
    List_z=[]
    Map= {}
    for z, x in dictionary.iteritems(): #iterate through the keys and values
        Map.setdefault(x,List_z).append(z) #Setdefault is the same as dict[key]=default."The method returns the key value available in the dictionary and if given key is not available then it will return provided default value. Afterward, we will append into the default list our new values for the specific key.
    return Map

0

วิธีแก้ปัญหาการทำงานที่รวดเร็วสำหรับแผนที่ที่ไม่ใช่ Bijective (ค่าไม่ซ้ำกัน):

from itertools import imap, groupby

def fst(s):
    return s[0]

def snd(s):
    return s[1]

def inverseDict(d):
    """
    input d: a -> b
    output : b -> set(a)
    """
    return {
        v : set(imap(fst, kv_iter))
        for (v, kv_iter) in groupby(
            sorted(d.iteritems(),
                   key=snd),
            key=snd
        )
    }

ในทฤษฎีนี้ควรจะเร็วกว่าการเพิ่มชุด (หรือผนวกกับรายการ) หนึ่งโดยหนึ่งเช่นเดียวกับในการแก้ปัญหาความจำเป็น

น่าเสียดายที่ค่าจะต้องมีการเรียงลำดับ Groupby ต้องการการเรียงลำดับ


1
"ในทางทฤษฎีสิ่งนี้ควรจะเร็วกว่าการเพิ่มเข้าไปในเซต (หรือต่อท้ายรายการ) ทีละตัว" - ไม่ nองค์ประกอบที่กำหนดใน dict ดั้งเดิมวิธีการของคุณมีO(n log n)ความซับซ้อนของเวลาเนื่องจากจำเป็นต้องจัดเรียงรายการของ dict ในขณะที่แนวทางที่ไร้เดียงสามีO(n)ความซับซ้อนของเวลา สำหรับทั้งหมดที่ฉันรู้วิธีการของคุณอาจเร็วขึ้นจนกว่าจะมีขนาดใหญ่ไร้สาระdictในทางปฏิบัติแต่แน่นอนว่ามันไม่เร็วกว่าในทางทฤษฎี
Mark Amery


-1

ฉันจะทำอย่างนั้นในหลาม 2

inv_map = {my_map[x] : x for x in my_map}

การทำซ้ำคู่ของคีย์ - ค่าพร้อมกันผ่านทางdict.items(หรือiteritemsใน Python 2) จะมีประสิทธิภาพมากกว่าการแยกแต่ละค่าแยกต่างหากในขณะที่ทำซ้ำคีย์
jpp

-1
def invertDictionary(d):
    myDict = {}
  for i in d:
     value = d.get(i)
     myDict.setdefault(value,[]).append(i)   
 return myDict
 print invertDictionary({'a':1, 'b':2, 'c':3 , 'd' : 1})

สิ่งนี้จะให้ผลลัพธ์เป็น: {1: ['a', 'd'], 2: ['b'], 3: ['c']}


การทำซ้ำคู่ของคีย์ - ค่าพร้อมกันผ่านทางdict.items(หรือiteritemsใน Python 2) จะมีประสิทธิภาพมากกว่าการแยกแต่ละค่าแยกต่างหากในขณะที่ทำซ้ำคีย์ นอกจากนี้คุณยังไม่ได้เพิ่มคำอธิบายสำหรับคำตอบที่ซ้ำกับคนอื่น
jpp

-1
  def reverse_dictionary(input_dict):
      out = {}
      for v in input_dict.values():  
          for value in v:
              if value not in out:
                  out[value.lower()] = []

      for i in input_dict:
          for j in out:
              if j in map (lambda x : x.lower(),input_dict[i]):
                  out[j].append(i.lower())
                  out[j].sort()
      return out

รหัสนี้ทำอย่างนี้:

r = reverse_dictionary({'Accurate': ['exact', 'precise'], 'exact': ['precise'], 'astute': ['Smart', 'clever'], 'smart': ['clever', 'bright', 'talented']})

print(r)

{'precise': ['accurate', 'exact'], 'clever': ['astute', 'smart'], 'talented': ['smart'], 'bright': ['smart'], 'exact': ['accurate'], 'smart': ['astute']}

1
โดยทั่วไปแล้วคำตอบจะมีประโยชน์มากขึ้นหากพวกเขามีคำอธิบายว่าควรใช้รหัสใดและเหตุใดจึงแก้ปัญหาได้โดยไม่ต้องแนะนำผู้อื่น
Tom Aranda

1
มันดีมาก แต่มีการตัดสินใจที่ไม่สามารถอธิบายได้มากมาย (เช่นทำไมตัวพิมพ์เล็กสำหรับคีย์)
Liudvikas Akelis

-2

ไม่ใช่สิ่งที่แตกต่างอย่างสิ้นเชิงเพียงสูตรการเขียนใหม่จากตำราอาหาร มันเป็นsetdefaultวิธีที่ได้รับการปรับให้เหมาะสมที่สุดโดยใช้วิธีการเก็บรักษาแทนการใช้แต่ละครั้งผ่านตัวอย่าง:

def inverse(mapping):
    '''
    A function to inverse mapping, collecting keys with simillar values
    in list. Careful to retain original type and to be fast.
    >> d = dict(a=1, b=2, c=1, d=3, e=2, f=1, g=5, h=2)
    >> inverse(d)
    {1: ['f', 'c', 'a'], 2: ['h', 'b', 'e'], 3: ['d'], 5: ['g']}
    '''
    res = {}
    setdef = res.setdefault
    for key, value in mapping.items():
        setdef(value, []).append(key)
    return res if mapping.__class__==dict else mapping.__class__(res)

ออกแบบมาเพื่อทำงานภายใต้ CPython 3.x สำหรับ 2.x แทนที่mapping.items()ด้วยmapping.iteritems()

บนเครื่องของฉันทำงานเร็วขึ้นเล็กน้อยกว่าตัวอย่างอื่น ๆ ที่นี่


1
การสร้างผลลัพธ์เป็น a dictและจากนั้นแปลงเป็นคลาสที่ต้องการในตอนท้าย (แทนที่จะเริ่มด้วยคลาสประเภทที่ถูกต้อง) ดูเหมือนว่าฉันจะได้รับประสิทธิภาพที่หลีกเลี่ยงได้อย่างสิ้นเชิงที่นี่
Mark Amery

-2

ฉันเขียนสิ่งนี้ด้วยความช่วยเหลือของวงจร 'for' และ method '.get ()' และฉันเปลี่ยนชื่อ 'map' ของพจนานุกรมเป็น 'map1' เพราะ 'map' เป็นฟังก์ชั่น

def dict_invert(map1):
    inv_map = {} # new dictionary
    for key in map1.keys():
        inv_map[map1.get(key)] = key
    return inv_map

-2

หากค่าไม่ซ้ำกันและอาจเป็นแฮช (หนึ่งส่วนข้อมูล):

for k, v in myDict.items():
    if len(v) > 1:
        for item in v:
            invDict[item] = invDict.get(item, [])
            invDict[item].append(k)
    else:
        invDict[v] = invDict.get(v, [])
        invDict[v].append(k)

และด้วยการเรียกซ้ำถ้าคุณต้องการขุดให้ลึกกว่านั้นเพียงมิติเดียว:

def digList(lst):
    temp = []
    for item in lst:
        if type(item) is list:
            temp.append(digList(item))
        else:
            temp.append(item)
    return set(temp)

for k, v in myDict.items():
    if type(v) is list:
        items = digList(v)
        for item in items:
            invDict[item] = invDict.get(item, [])
            invDict[item].append(k)
    else:
        invDict[v] = invDict.get(v, [])
        invDict[v].append(k)

คุณอาจปรับปรุงวิธีแก้ปัญหาของคุณโดยใช้ defaultdict: มันจะลบบรรทัด invDict ทั้งหมด [รายการ] = invDict.get (รายการ, []) บรรทัด
gabuzo

วิธีการแรกของคุณที่นี่แปลง{"foo": "bar"}เป็น{'b': ['foo'], 'a': ['foo'], 'r': ['foo']}และยกข้อยกเว้นหากค่าใด ๆ ในmyDictนั้นไม่สามารถทำซ้ำได้ ฉันไม่แน่ใจว่าพฤติกรรมที่คุณพยายามนำมาใช้ที่นี่ แต่สิ่งที่คุณนำมาใช้จริงเป็นสิ่งที่ไม่มีใครต้องการ
Mark Amery
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.