Merge dictionary keys if the values ​​are the same

So this is a strange problem that I suspect is very easy to solve. I am creating webapp lyrics for remote players in my home. He is currently creating a dictionary of players with the song they are playing. For instance:

{ 'bathroom': <Song: Blur - Song 2>, 'bedroom1': <Song: Blur - Song 2>, 'kitchen': <Song: Meat Loaf - I'd Do Anything for Love (But I Won't Do That)>, } 

Sometimes subsets of these players are synchronized. So - above - they display the same value. I would like to group them in an interface. I could be more intelligent when I create a dictionary, but I guess I won’t do it, is there a good way to combine keys by value

The desired result from the above will look something like this:

 { 'bathroom,bedroom1': <Song: Blur - Song 2>, 'kitchen': <Song: Meat Loaf - I'd Do Anything for Love (But I Won't Do That)>, } 

However, this violates the way I would like to search for things (I would like to indicate by name, therefore, this is a dictionary) ... Is there a better collection that can have several keys for each value and indicate when there are merged duplicates (and back - all keys)?


There is a good answer that flips this over to the key to the songs and the list of players as a value. This is great, except sometimes I want to know which song is playing on the player’s name. That is why I originally went with the dictionary.

Is there a good way to save a search in both directions (without waiting for both collections to be saved)?

+5
source share
2 answers

When the amount of significant data is significant, this is the type of thing where a relational database comes in handy. A database with two columns, a key and a value and an index in the key column acts as a voice recorder. But you can also put an index in a value column to provide an efficient reverse lookup.

In your case, however, since the amount of data is small, I just make defaultdict and add (value, key) pairs.

 reverse_lookup = defaultdict(list) for k, v in now_playing.items(): reverse_lookup[v].append(k) 

And then you can ','.join() values ​​to create compound keys. Since these composite keys will be used for display, it seems that it is actually not for searching, I would just keep both the original dict and the reverse dict search in memory and use what you need when you need to search, The task of finding others players who play the same song as this one (and presumably synchronized) then include two searches, one forward and one backward, but they have hash tables, so the added value is minimal.


After some thought of other, more “interesting” ways to do this: you can pervert the disjoint set data structure to meet your needs. You will have a node for each player and a node for each song being played. Nodes are grouped by sets of songs, where one set contains both a node for a song and nodes for any players currently playing this song. If you put each set of nodes (song plus players) in a cyclically linked list while the overall data structure is properly maintained, you can start from any node and skip the list to iterate over both the song and the list of players who play this song.

The trick, of course, finds an efficient way to maintain this general data structure, i.e. Update looping lists as songs change. If the players are truly synchronized, it's as simple as replacing one node song with another, every time the whole group of players moves to the next track. But I can imagine that an application like the one you are creating often has to do other kinds of searches for which the structure of unrelated sets does not do you any good.

+2
source
 from itertools import groupby x = { 'bathroom': 'a', 'bedroom1': 'a', 'kitchen': 'b' } { ','.join(i[0] for i in v): k for k,v in groupby(sorted(x.iteritems(), key=lambda p: p[1]), lambda p: p[1]) } 
+7
source

Source: https://habr.com/ru/post/1236612/


All Articles