TransWikia.com

How to create a nested dictionary from existing dictionary with set and list of tuples

Stack Overflow Asked on November 7, 2021

I have parsed a midi file, and I’ve successfully gotten a dictionary of notes broken up by instrument. An abbreviated example of this is note_dict below, truncated for the purposes of this question.

My end goal is to have a nested dictionary that provides me with the track name, then each possible note as a key, then a list of all possible "next" notes as values. The intent is to use this in as a Markov chain in Foxdot, a python interface for music generation.

It should look something like:

{'track1': {note: [note1, note2, note3], note2: [note1, note2, note3]}, 'track2': {note: [note1, note2, note3], note2: [note1, note2, note3]}

Here is an example of what I have:

import itertools 

def pairwise(iterable):
    a, b = itertools.tee(iterable)
    next(b, None)
    return list(zip(a, b))

note_dict = {'Vocal': [-2, -2, -1, -2], 'Guitar': [1, 1, 4, 1, -2, 1]}

note_dict_updated = { track: [{ n for n in notes }, pairwise(notes), notes] for track, notes in note_dict.items() }
print(note_dict_updated)

This gives me the following, where the first set is all distinct notes, the list of tuples is a pairing of (note, next note), and the last list is just a raw list of notes in order.

{'Vocal': [{-2, -1}, [(-2, -2), (-2, -1), (-1, -2)], [-2, -2, -1, -2]], 'Guitar': [{1, 4, -2}, [(1, 1), (1, 4), (4, 1), (1, -2), (-2, 1)], [1, 1, 4, 1, -2, 1]]}

I’d like the elements of the sets to act as keys, and when the first element of the tuple matches an element of the set, it is added to a list of values associated with the key.

My desired end result, based on note_dict above is:

{'Vocal': {-2: [-2, -1], -1: [-2]}, 'Guitar': {1: [1, 4, -2], 4: [1], -2: [1]}}

All that said, I am not locked into the method where I need to work with note_dict_updated. If there is a smarter way to get from note_dict to my desired end result, I’d love to hear.

edit: I’ve updated my question a bit. The first answer worked for my initial example, but I believe there are issues when the list of notes in each value overlap. Hopefully, my updated desired end result will be more helpful.

One Answer

The first loop creates an intermediary dictionary of dictionary with inner keys and the same unique sets. This is then cleaned with a second a for-loop as shown here:

Input:

{'Vocal': [-2, -2, -1, -2], 'Guitar': [1, 1, 4, 1]}

Output:

{'Guitar': {1: [1, 4], 4: [1]}, 'Vocal': {-2: [-1, -2], -1: [-2]}}

Code:

#create a new dictionary of dictionary with inner keys and same unique sets

note_dict_updated={}
for key, value in note_dict.iteritems():
    note_dict_updated[key]={}
    for element in set(note_dict[key]):
        note_dict_updated[key][element]=list(set(note_dict[key]))

# remove the values (of not interest) from list values of inner keys 
for key, value in note_dict_updated.iteritems():
    comb=[]
    for lkey, lvalue in note_dict_updated[key].iteritems():
        for val in lvalue:
            if (val,lkey) in comb:
                try:
                    note_dict_updated[key][lkey].remove(lkey)
                except ValueError as e:
                    print ('Issue in key {} for subkey {}'.format(key,lkey))
        for val in lvalue:
            comb.append((lkey,val))

Answered by Sameeresque on November 7, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP