I have a list with nested tuples, like the one below:
data = [('apple', 19.0, ['gala', '14', 'fuji', '5', 'dawn', '3', 'taylor', '3']),
('pear', 35.0, ['anjou', '29', 'william', '6', 'concorde', '4'])]
I want to flatten it out so that I can write a .csv file in which each item on every list corresponds to a column:
apple 19.0, gala 14 fuji 5 dawn 3 taylor 3
pear 35.0 anjou 29 william 6 concorde 4
I tried using simple flattening:
flattened = [value for pair in data for value in pair]
But the outcome has not been the desired one. Any ideas on how to solve this?
To write out the data to CSV, simply use the csv module and give it one row; constructing the row is not that hard:
import csv
with open(outputfile, 'w', newlines='') as ofh:
writer = csv.writer(ofh)
for row in data:
row = list(row[:2]) + row[2]
writer.writerow(row)
This produces:
apple,19.0,gala,14,fuji,5,dawn,3,taylor,3
pear,35.0,anjou,29,william,6,concorde,4
Disclaimer - Not very efficient Python code.
But, it does the job. (You can adjust the width (currently 10))
data = [('apple', 19.0, ['gala', '14', 'fuji', '5', 'dawn', '3', 'taylor', '3']),
('pear', 35.0, ['anjou', '29', 'william', '6', 'concorde', '4'])]
flattened = list()
for i, each in enumerate(data):
flattened.append(list())
for item in each:
if isinstance(item, list):
flattened[i].extend(item)
else:
flattened[i].append(item)
# Now print the flattened list in the required prettified manner.
for each in flattened:
print ("".join(["{:<10}".format(item) for item in each]))
# String is formatted such that all items are width 10 & left-aligned
Note - I tried to write the function for a more general case.
PS - Any code suggestions are welcome. I really want to improve this one.
This seems like it calls for recursion
def flatten(inlist):
outlist=[]
if isinstance(inlist, (list, tuple)):
for item in inlist:
outlist+=flatten(item)
else:
outlist+=[inlist]
return outlist
This should work no matter how nested your list becomes. Tested it with this:
>>> flatten([0,1,2,[3,4,[5,6],[7,8]]])
[0, 1, 2, 3, 4, 5, 6, 7, 8]
Related
This question already has answers here:
A better way to create a dictionary out of two lists with duplicated values in one
(2 answers)
Closed 1 year ago.
I have a question making a dictionary with text file.
I have a text file like this:
0,1
0,2
0,3
1,2
1,3
1,4
2,3
2,4
2,5
What I am trying to do,
I would like to make {0: [1,2,3], 1:[2,3,4], 2:[3,4,5]} like this
lists = {}
test = open('Test.txt', mode='r', encoding = 'utf-8').read().split('\n')
for i in test:
if len(lists) == 0:
lists[i.split(',')[0]] = [i.split(',')[1]]
In here, whenever I call for fuction, the value number is changed..
I am trying to figure out how I gotta do,
But it seems little bit tricky to me
Can anyone give me some advice or direction for it?
I really appreciate it
Thank you!
result = {}
with open('test.txt') as f:
for line in f:
key, value = line.strip().split(',')
if key not in result:
result[key] = [value]
else:
result[key].append(value)
print(result)
Output:
{'0': ['1', '2', '3'], '1': ['2', '3', '4'], '2': ['3', '4', '5']}
You can also try the defaultdict collection which is more convinent.
Here is an approach with a defaultdict. map with the reference to the int function is used to convert the strings to integers.
from collections import defaultdict
result = defaultdict(list)
with open('Test.txt', mode='r', encoding='utf-8') as infile:
for line in infile:
key, value = map(int, line.split(','))
result[key].append(value)
print(result)
The result is
defaultdict(<class 'list'>, {0: [1, 2, 3], 1: [2, 3, 4], 2: [3, 4, 5]})
Besides the bonus of the default value it will behave like a normal dictionary.
I have the following lists:
main_list:
[4, 1, 5]
iterated lists/two rows from dict:
['John', '1', '4', '3']
['Mary', '4', '1', '5']
the iterated list is from the below, dictionary being csv.DictReader(x):
for row in dictionary:
print(list(row.values()))
I want the below to work, where if my main_list matches a sequence from the dictionary list, it will spit out the first column, in which the header is 'name':
if main_list in list(row.values()):
print(row['name'])
For the example above, as Mary's items match 4, 1, 5, the final returned value should be Mary.
I'm new to Python, and I would appreciate any advice on how to work this out.
You can use extended tuple unpacking to split a row into its name and the rest.
name,*therest = `['Mary', '4', '1', '5']
Then make the comparison
test = [4, 1, 5]
if therest == [str(thing) for thing in test]:
print(name)
keys = ['key1', 'key2', 'key3', 'key4']
list1 = ['a1', 'b3', 'c4', 'd2', 'h0', 'k1', 'p2', 'o3']
list2 = ['1', '2', '25', '23', '4', '5', '6', '210', '8', '02', '92', '320']
abc = dict(zip(keys[:4], [list1,list2]))
with open('myfilecsvs.csv', 'wb') as f:
[f.write('{0},{1}\n'.format(key, value)) for key, value in abc.items()]
I am getting all keys in 1st column with this and values in other column respectively.
What I am trying to achieve is all keys in first row i-e each key in specific column of first row and then their values below. Something like transpose
I willbe much grateful for your assist on this
You can use join and zip_longest to do this.
",".join(abc.keys()) will return first row (the keys) like key1,key2,and then use zip_longest(Python2.x use izip_longest) to aggregate elements.And use the same way append , and \n to the string.
zip_longest
Make an iterator that aggregates elements from each of the iterables.
If the iterables are of uneven length, missing values are filled-in
with fillvalue.
from itertools import zip_longest
with open('myfilecsvs.csv', 'w') as f:
f.write("\n".join([",".join(abc.keys()),*(",".join(i) for i in zip_longest(*abc.values(),fillvalue=''))]))
Output:
key1,key2
a1,1
b3,2
...
,02
,92
,320
I have a list of data that is in the structure of name and then score like this:
['Danny', '8', 'John', '5', 'Sandra', 10]
What I require to do in the simplest way possible is sort the data by lowest to highest score for example like this:
['John', '5', 'Danny', '8', 'Sandra', 10]
You should create pairings which will make your life a lot easier:
l = ['Danny', '8', 'John', '5', 'Sandra', '10']
it = iter(l)
srt = sorted(zip(it, it), key=lambda x: int(x[1]))
Which will give you:
[('John', '5'), ('Danny', '8'), ('Sandra', '10')]
it = iter(l) creates an iterator, then zip(it, it) basically calls (next(it), next(it)) each iteration so you create pairs of tuples in the format (user, score), then we sort by the second element of each tuple which is the score, casting to int.
You may be as well to cast to int and then sortif you plan on using the data, you could also create a flat list from the sorted data but I think that would be a bad idea.
The best data structure for your problem is Dictionary.
In your situatiton you need to map between names and scores.
dict = {'Danny':'8', 'John':'5', 'Sandra':'10'}
sorted_dict = ((k, dict[k]) for k in sorted(dict, key=dict.get, reverse=False))
for k, v in genexp:
... k, v
('John', '5')
('Danny', '8')
('Sandra', 10)
I just learn python for not long. And I had try my best to represent my data looks better just like showing before.
Now I have some tuple data type which look like this:
('John', '5', 'Coke')
('Mary', '1', 'Pie')
('Jack', '3', 'Milk')
('Mary', '2', 'Water')
('John', '3', 'Coke')
And I wanna count how many items that each one had bought.
Assume that the different name is different person.
So how could I do in order to get some information like this below:
John: 8 Coke
Mary: 1 Pie
Mary: 2 Water
Jack: 3 Milk
I have no idea how could I do now. I can't come up with any method even the stupid one.
I'd suggest using name and drink as a key for collections.Counter:
from collections import Counter
count = Counter()
for name, amount, drink in tuples:
key = name, drink
count.update({key: int(amount)}) # increment the value
# represent the aggregated data
for (name, drink), amount in count.items():
print('{}: {} {}'.format(name, amount, drink))
Update I made some simple measurements, and figured out that
count[name, drink] += value
is not only more readable, but much faster than calling update, which should not be a surprise. Moreover, defaultdict(int) is even faster (about twice) than that (presumably, because Counter performs some ordering additionally.)
Re-arranging the order of your data might help:
John: 8 Coke
Mary: 1 Pie
Mary: 2 Water
Jack: 3 Milk
might be more insightful, when written as
(John, Coke) : 8
(Mary, Pie) : 1
(Mary, Water): 2
(Jack, Milk) : 3
If you know SQL, this is more or less equivalent to groupby(name, dish) together with sum(count).
So, in Python, you can create a dictionary for that pair:
data = [
('John', '5', 'Coke'),
('Mary', '1', 'Pie'),
('Jack', '3', 'Milk'),
('Mary', '2', 'Water'),
('John', '3', 'Coke'),
]
orders = {}
for name, count, dish in data:
if (name, dish) in orders:
orders[(name, dish)] += int(count)
else:
# first entry
orders[(name, dish)] = int(count)
Even more pythonic, use collections.defaultdict:
orders = defaultdict(int)
for name, count, dish in data:
orders[(name, dish)] += int(count)
or collections.Counter as noted by #bereal.
Format data as you like.
Assuming you have a list of tuples
tuples = [('John', '5', 'Coke'),
('Mary', '1', 'Pie'),
('Jack', '3', 'Milk'),
('Mary', '2', 'Water'),
('John', '3', 'Coke')]
memory = {}
# First, we calculate the amount for each pair
for tuple in tuples:
# I define a generated key through the names. For example John-Cake, Mary-Pie, Jack-Milk,...
key = (tuple[0],tuple[2])
number = int(tuple[1])
if key in memory:
memory[key] += number
else:
memory[key] = number
# After, we format the information
list = []
for key in memory:
list.append((key[0],memory[key],key[1]))