This question already has answers here:
How to sum up a list of tuples having the same first element?
(5 answers)
How to perform a groupby operation in Python on a list of tuples where we need to sum the second element? [duplicate]
(1 answer)
Closed 10 months ago.
Convert a nested list from [[...],[...]] to [(...),(...)]. I wish to format my list below :
x=[['dog', 2], ['bird', 1],['dog',1]]
to
x=[('dog', 3), ('bird', 1)]
Here is my code for reference.
#Convert last element of nested list to int
newlist = [[int(element) if element.isdigit() else element for element in sub for sub in x]
#add the 2 columns that match
grouped = dict()
grouped.update((name,grouped.get(name,0)+value) for name,value in newlist)
x = [*map(list,grouped.items())]
Could this be due to my use of a dict()
I have been successful with adding the second indices given that the first ones match, however the result is being formatted as such
x=[['dog', 3], ['bird', 1]]
however, I would like it as so any advice on how to get this ideal output?
x=[('dog', 3), ('bird', 1)]
I guess you are looking for collections.Counter:
from collections import Counter
x=[['dog', 2], ['bird', 1],['dog',1]]
c = Counter()
for k, v in x:
c[k] += v
print(c)
# as pointed out by wim in the comments, use the below
# to get a list of tuples:
print([*c.items()])
Here is one way to do so:
x = [['dog', 2], ['bird', 1], ['dog', 1]]
data = {k: 0 for k, _ in x}
for key, num in x:
data[key] += num
print(list(data.items())) # [('dog', 3), ('bird', 1)]
You can also use setdefault():
data = {}
for key, num in x:
data.setdefault(key, 0)
data[key] += num
print(list(data.items()))
looks like this works
newlist = [int(element) if element[0].isdigit() else element for element in [sub for sub in x]]
# add the 2 columns that match
grouped = dict()
grouped.update((name, grouped.get(name, 0) + value) for name, value in newlist)
x = [*map(tuple, grouped.items())]
Don't make it a list in the first place. The only real thing to note here is replacing list with tuple however, I also removed the unpacking ([*...]) and went directly to casting the parent as a list.
change:
x = [*map(list,grouped.items())]
to:
x = list(map(tuple, grouped.items()))
x=[['dog', 3], ['bird', 1]]
# You want it to be...
x=[('dog', 3), ('bird', 1)]
So you should first know how to convert ['dog', 3] to ('dog', 3):
>>> x = ['dog', 3]
>>> tuple(x)
('dog', 3)
To make it a tuple you just have to use the tuple's class constructor.
Then you have to apply this to the whole x list:
x = [tuple(i) for i in x]
Related
I was wondering if you could help me simplify my code or find an efficient method. I am given a nested array and I wish to add the second element based on the first nested item.
[('dog','1'),('dog','2'),('cat',1'),('cat','2')]
This will result in:
[('dog','3'),('cat','3')]
I would want the numbers to be strings instead of int type. Here is my code below:
dddd=[]
dddd=result_1_ce+result_2_ce+result_3_ce+result_4_ce
#Sum all of the elements from a prior find dddd stores [('dog','1'),('dog','2'),('cat',1'),('cat','2')]
newlist = [[int(element) if element.isdigit() else element for element in sub] for sub in dddd]
grouped = dict()
grouped.update((name,grouped.get(name,0)+value) for name,value in newlist)
dddd = [*map(list,grouped.items())]
#Of this manipulation display it in reverse order
dddd=sorted(dddd,key=lambda x:x[1],reverse=True)
X = [tuple(i) for i in dddd]
print("Findings:",X)
This code work
I am writing a comment where I change the code.
dddd=result_1_ce+result_2_ce+result_3_ce+result_4_ce
#Sum all of the elements from a prior find dddd stores [('dog','1'),('dog','2'),('cat',1'),('cat','2')]
newlist = [[int(element) if element.isdigit() else element for element in sub] for sub in dddd]
grouped = dict()
grouped.update((name,grouped.get(name,0)+value) for name,value in newlist)
dddd = [*map(list,grouped.items())]
#Of this manipulation display it in reverse order
dddd=sorted(dddd,key=lambda x:x[1],reverse=True)
X = [tuple([f,str(s)]) for f,s in dddd] # get two both element from the list of list and change second('s) element to str.
print("Findings:",X)
OUTPUT
Findings: [('dog', '3'), ('cat', '3')]
You dddd list is looks like this [['dog', 3], ['cat', 3]].
# If I write This
dddd = [['dog', 3], ['cat', 3]]
for f,s in dddd: # (f is for 'dog' and 'cat) and (s is for 3 and 3)
print(f)
print(s)
It seems to me, a very simple approach would be to convert to a dictionary first, and it is a good data structure for grouping. Also, use an integer to sum the numbers. You can use int of str if you are unsure if each number value will be int or str. Then to get the output of list of tuples, you just convert with a simple comprehension.
l = [("dog", "1"), ("dog", "2"), ("cat", 1), ("cat", "2")]
d = {}
for t in l:
d[t[0]] = d.setdefault(t[0], 0) + int(str(t[1]))
print([(k, str(v)) for k, v in d.items()])
Output:
[('dog', '3'), ('cat', '3')]
This question already has an answer here:
What's the most Pythonic way to identify consecutive duplicates in a list?
(1 answer)
Closed 10 months ago.
I have string value as:
s = 'asdabbdasfababbabb'
I've split the str by using below code, than get result as below :
n = 3
split_strings = [s[index : index + n] for index in range(0, len(s), n)]
['asd', 'abb', 'das', 'fab', 'abb', 'abb']
What I need to achieve:
I want to count duplicated value consiering the sequence such as :
({'asd': 1, 'abb': 1, 'das': 1, 'fab': 1, 'abb' : 2})
However, if I use Counter() it counts the duplicated value but, does not seems to consider the sequence of list:
Counter({'asd': 1, 'abb': 3, 'das': 1, 'fab': 1})
How can I achieve what I need?
You cannot store duplicate keys in a dict. If you are willing to have a list of tuples, you can use itertools.groupby:
from itertools import groupby
lst = ['asd', 'abb', 'das', 'fab', 'abb', 'abb']
counts = [(k, len([*g])) for k, g in groupby(lst)]
print(counts) # [('asd', 1), ('abb', 1), ('das', 1), ('fab', 1), ('abb', 2)]
The itertools.groupby function is a favorite, but perhaps future readers might appreciate an algorithm for actually finding these groupings:
def groups(*items):
i = 0
groups = []
while i < len(items):
item = items[i]
j = i + 1
count = 1
while j < len(items):
if items[j] == item:
count += 1
j += 1
else:
break
i = j
groups.append((item, count))
return groups
I have a dictionary of lists.
I want to count the number of empty and non-empty lists and print the first element of the non-empty ones at the same time.
Is there a more elegant(Python-like) way of doing it?
incorrect = 0
correct = 0
for key, l in dictionary.items():
try:
print(l[0])
correct += 1
except IndexError:
incorrect += 1
pass
print("Number of empty lists: ", incorrect)
print("Number of non-empty lists: ", correct)
A list comprehension seems like it would work well here. Assuming I've understood your question correctly you currently have a dictionary which looks something like this:
list_dict = {"list_1": [1], "list_2": [], "list_3": [2, 3]}
So you can do something like this:
first_element_of_non_empty = [l[0] for l in list_dict.values() if l]
Here we make use of the fact that empty lists in python evaluate to False in boolean comparisons.
Then to find counts is pretty straightforward, obviously the number of non empty lists is just going to be the length of the output of the comprehension and then the empty is just the difference between this number and the total entries in the dictionary.
num_non_empty = len(first_element_of_non_empty)
num_empty = len(list_dict) - num_non_empty
print("Number of empty arrays: ", num_empty)
print("Number of non-empty arrays: ", num_non_empty)
Get the first non-empty item:
next(array for key, array in dictionary.items() if array)
Count empty and none empty items:
correct = len([array for key, array in dictionary.items() if array])
incorrect = len([array for key, array in dictionary.items() if not array])
You can use filter(None, [...]) to remove values that evaluate to False, and then use map to retrieve the first elements of those values.
At the Python (3.7.3) command line:
>>> d = {'a': [1], 'b': [], 'c': [3, 4]}
>>>
>>> first_elements = tuple(map(
... lambda v: v[0],
... filter(None, d.values()),
... ))
>>> non_empty_count = len(first_elements)
>>> empty_count = len(d) - non_empty_count
>>>
>>> print(first_elements, non_empty_count, empty_count)
(1, 3) 2 1
How to write a function to rearrange a list according to the dictionary of index in python?
for example,
L=[('b',3),('a',2),('c',1)]
dict_index={'a':0,'b':1,'c':2}
I want a list of :
[2,3,1]
where 2 is from 'a',3 is from 'b' and 1 is from 'c', but rearrange only the number in L according to the dict_index
Try this (edited with simpler solution):
L=[('b',3),('a',2),('c',1)]
dict_index={'a':0,'b':1,'c':2}
# Creates a new empty list with a "slot" for each letter.
result_list = [0] * len(dict_index)
for letter, value in L:
# Assigns the value on the correct slot based on the letter.
result_list[dict_index[letter]] = value
print result_list # prints [2, 3, 1]
sorted and the .sort() method of lists take a key parameter:
>>> L=[('b',3),('a',2),('c',1)]
>>> dict_index={'a':0,'b':1,'c':2}
>>> sorted(L, key=lambda x: dict_index[x[0]])
[('a', 2), ('b', 3), ('c', 1)]
and so
>>> [x[1] for x in sorted(L, key=lambda x: dict_index[x[0]])]
[2, 3, 1]
should do it. For a more interesting example -- yours happens to match alphabetical order with the numerical order, so it's hard to see that it's really working -- we can shuffle dict_index a bit:
>>> dict_index={'a':0,'b':2,'c':1}
>>> sorted(L, key=lambda x: dict_index[x[0]])
[('a', 2), ('c', 1), ('b', 3)]
Using list comprehensions:
def index_sort(L, dict_index):
res = [(dict_index[i], j) for (i, j) in L] #Substitute in the index
res = sorted(res, key=lambda entry: entry[0]) #Sort by index
res = [j for (i, j) in res] #Just take the value
return res
I have a list of tuples of the form (a,b,c,d) and I want to copy only those tuples with unique values of 'a' to a new list. I'm very new to python.
Current idea that isn't working:
for (x) in list:
a,b,c,d=(x)
if list.count(a)==1:
newlist.append(x)
If you don't want to add any of the tuples that have duplicate a values (as opposed to adding the first occurrence of a given a, but none of the later ones):
seen = {}
for x in your_list:
a,b,c,d = x
seen.setdefault(a, []).append(x)
newlist = []
for a,x_vals in seen.iteritems():
if len(x_vals) == 1:
newlist.append(x_vals[0])
You could use a set to keep track of the duplicates:
seen_a = set()
for x in list:
a, b, c, d = x
if a not in seen_a:
newlist.append(x)
seen_a.add(x)
values = {}
for t in tups:
a,b,c,d = t
if a not in values:
values[a] = (1, t)
else:
count, tup = values[a]
values[a] = (count+1, t)
unique_tups = map(lambda v: v[1],
filter(lambda k: k[0] == 1, values.values()))
I am using a dictionary to store a values and the tuples that have that a value. The value at that key is a tuple of (count, tuple) where count is the number of times that a has been seen.
At the end, I filter the values dictionary for only those a values where the count is 1, i.e. they are unique. Then I map that list to return only those tuples, since the count value will be 1.
Now, unique_tups is a list of all those tuples with unique a's.
Updated after receiving feedback from commenters, thanks!
you could indeed sort the list and then iterate over it:
xs = [(1,2,3,4), (5, 2, 3, 4), (2, 3, 3, 3), (1, 5, 2, 3)]
newList = []
xs.sort()
lastX = None
for x in xs:
if lastX:
if lastX[0] == x[0]:
lastX = None
else:
newList.append(lastX)
lastX = x
if lastX:
newList.append(lastX)