简体   繁体   中英

Create a dictionary from list of tuples based on first element

I have a list of tuples that look like this:

[('name', 'Name'),('name','Age'),('name','Hometown'),('value','Bob'),('value',27),('value','Chicago'),('name','Home Team'),('name','Away Team'),('name','Score'),('value','Broncos'),('value','Patriots'),('name','Month'),('value','January'),...]

Essentially what this is is a bunch of tables. For example, the first table would have the headers 'Name', 'Age', and 'Hometown' and the entry would be 'Bob', 27, 'Chicago'.

I am trying to turn this into one dictionary like this: {'Name':'Bob','Age':27,'Hometown':'Chicago, 'Home Team':'Broncos',...}

I believe I can do this in a normal case, however if you look at the second "table" there are 3 headers and only 2 values. Is there a way to map the first two 'names' in that case to the first two 'values' and map the third ( 'Score' ) to an empty string?

ol = [('name', 'Name'),
      ('name','Age'),
      ('name','Hometown'),
      ('value','Bob'),
      ('value',27),
      ('value','Chicago'),
      ('name','Home Team'),
      ('name','Away Team'),
      ('name','Score'),
      ('value','Broncos'),
      ('value','Patriots'),
      ('name','Month'),
      ('value','January')]
l = ol.copy()
d = {}
noValue = False
while len(l) > 0 :
    i = 1
    while l[i][0] != 'value':
        i += 1
    d[l[0][1]] = l[i][1]
    if i == 2 and l[i+1][0] == 'name':
        d[l[1][1]] = ''
        l = l[i + 1:]
    else:
        l = l[1:i] + l[i + 1:]

print(d)

Printing:

{'Name': 'Bob', 'Age': 27, 'Hometown': 'Chicago', 'Home Team': 'Broncos', 'Away Team': 'Patriots', 'Score': '', 'Month': 'January'}

This should work as long as only the last value is missing. This list will not work [('name','Home Team'), ('name','Away Team'), ('name','Score'), ('value','Broncos'), ('name','Month'), ('value','January')]

Here is a solution I propose:

from itertools import zip_longest

tup = [('name', 'Name'),('name','Age'),('name','Hometown'),('value','Bob'),('value',27),('value','Chicago'),('name','Home Team'),('name','Away Team'),('value','Broncos'),('value','Patriots'),('name','Month'),('value','January'), ('name','Score')]

 names = [item[1] for item in tup if item[0] == "name"]
 values = [item[1] for item in tup if item[0] == "value"]
 d = dict(zip_longest(names, values, fill_value=""))

Output:

{'Name': 'Bob', 'Age': 27, 'Hometown': 'Chicago', 'Home Team': 'Broncos', 'Away Team': 'Patriots', 'Month': 'January', 'Score': ''}

You could use the standard zip() function but as you said, you need to map the surplus keys to an empty string. For that purpose, use itertools.zip_longest . And, remember that order is everything while zipping two iterables. In your question, the tuple ("name", "Score") comes before ("name", "Month") , and the last "value" is ("value", "January") . This would map "Score" to January and not "Month". So, I changed the order in my example.

Hope this helped:)

I think this works. May not be real pretty, but it should be rugged if you have several segments with missing values, and does not require altering the original list... Although I just learned zip_longest . Thanks @Zunayn

A little while loop construct can chew through this:

data = [('name', 'Name'),('name','Age'),('name','Hometown'),('value','Bob'),('value',27),('value','Chicago'),
('name','Home Team'),('name','Away Team'),('name','Score'),('value','Broncos'),('value','Patriots'),('name','Month'),('value','January')]

# reverse the data for more efficient pop()
data = data[::-1]

results = {}
d = data.pop()
while data:
    keys = []
    while d[0] == 'name':
        keys.append(d[1])
        d = data.pop()
    values = []
    while d[0] == 'value':
        values.append(d[1])
        if data:   # need to watch for end of list
            d = data.pop()
        else:
            break
    missing = len(keys) - len(values)
    values.extend(['na']*missing)

    # zip intermediate results and add to result
    results.update({k:v for (k, v) in zip(keys, values)})

print(results)

Yields:

{'Name': 'Bob', 'Age': 27, 'Hometown': 'Chicago', 'Home Team': 'Broncos', 'Away Team': 'Patriots', 'Score': 'na', 'Month': 'January'}

I just suggest, maybe do something like this. Of cource it will work if you names and values are stored in order.

  1. Start with pulling tuples with key 'name' from list and stop if occur 'value' tuple.
  2. Create dictionary from that keys, where every value is empty string temporarily.
  3. Go back to list and pull values and set in order into dict.
  4. If another 'name' tuple occurs, then go back to point 1. If there is no value for some key in previous dict, then it will be empty string.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM