sorting a list of tuples - python

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)

Related

Filter out tuples with only one element

I have a tuple containing coordinates for a list of nodes. The process I am attempting to complete needs a tuple with only 2-tuple or 3-tuples. I am trying to filter out any 1-tuples.
G=nx.read_shp(r'C:\TestData\tl_2019_36013_roads.shp')
pos = {k: v for k,v in enumerate(G.nodes())}
X=nx.Graph() #Empty graph
X.add_nodes_from(pos.keys()) #Add nodes preserving coordinates
edg=[tuple(k for k,v in pos.items() if v in sl) for sl in l]
print(edg)
A portion of this output is:
[(38, 9848), (40, 41), (40,), (10, 42)]
So in this case, I am attempting to filter out the entry: (40,) as it is only a 1-tuple.
I guess the fastest and most pythonic way to filter this input is to use filter :)
filtered = filter(lambda x: len(x) > 1, input_list)
tuplelist = (40,), (40,21), (532, 234)
newlist = []
for i in tuplelist:
if len(i) != 1:
newlist.append(i)
using the len function, you can check if the length is not 1
you can also do this:
tuplelist = (40,), (40,21), (532, 234)
newlist = []
[newlist.append(i) for i in tuplelist if len(i) != 1]

Convert a nested list from [[...],[...]] to [(...),(...)] [duplicate]

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]

How can I compare two nested lists and counting number of occurences and keep into a dictionary

I have two nested lists,
l1 = [[1],[2],[1,2],[3],[2,2]]
l2 = [[1],[3],[3,4],[1],[1,2],[3],[4],[1],[2],[1,2],[3],[2,2]]
I want to figure out how many times each element of l1 find out in l2 and keep the value into a dictionary where the key of a dictionary is the number of occurrences of each element and value will be the element itself. what I did as follows:
dic = {}
for item in l1:
count = 0
for items in l2:
if item == items:
count += 1
dic[count] = item
return dic
The answer would be dic = {3:[1], 1:[2], 2:[1,2], 3:[3], 1:[2,2]}
But I got dic = {1:[2], 2:[1,2], 3:[3]}. I didn't get the exact answer. Could you please help me how to fix this problem?
The problem is that you have multiple items in l1 having identical counts.
Both [2,2] and [2] each occur once, so when they are assigned into the dictionary on overwrites the other.
Reverse this line:
dic[count] = item
to this:
dic[item] = count
keep in mind that you can't have duplicate keys in a dictionary so your requested output is impossible!
l1 = [[1],[2],[1,2],[3],[2,2]]
l2 = [[1],[3],[3,4],[1],[1,2],[3],[4],[1],[2],[1,2],[3],[2,2]]
dic = {}
for i in l1:
item = tuple(i)
count = 0
for j in l2:
items = tuple(j)
if item == items:
count += 1
dic[item] = count
print dic
Output:
{(1, 2): 2, (2,): 1, (3,): 3, (1,): 3, (2, 2): 1}
dict key is list and value is count

How to check for a value in a list of tuples?

I have a list of tuples like this:
l = [(10,'bat'), (50,'ball'), (100,'goal')]
and I want to check if 100 is in any of the tuples. And if it is there I need to remove its value which is 'goal'.
How can I do this?
TIA
You can use list comprehension to filter out the tuple:
l = [t for t in l if t[0] != 100]
If you want/have to do this with multiple values, you can create a set of them:
exclude = set(100, 30, 20)
l = [t for t in l if t[0] not in exclude]
Checks for 100 in any column and removes 100 from tuple.
l = [(10,'bat'), (50,'ball'), (100,'goal')]
for i, row in enumerate(l[:]):
if any(col == 100 for col in row):
new_row = filter(lambda col: col != 100, row)
l[i] = new_row
print l

Delete item in a list using a for-loop

I have an array with subjects and every subject has connected time. I want to compare every subjects in the list. If there are two of the same subjects, I want to add the times of both subjects, and also want to delete the second subject information (subject-name and time).
But If I delete the item, the list become shorter, and I get an out-of-range-error. I tried to make the list shorter with using subjectlegth-1, but this also don't work.
...
subjectlegth = 8
for x in range(subjectlength):
for y in range(subjectlength):
if subject[x] == subject[y]:
if x != y:
#add
time[x] = time[x] + time[y]
#delete
del time[y]
del subject[y]
subjectlength = subjectlength - 1
Iterate backwards, if you can:
for x in range(subjectlength - 1, -1, -1):
and similarly for y.
If the elements of subject are hashable:
finalinfo = {}
for s, t in zip(subject, time):
finalinfo[s] = finalinfo.get(s, 0) + t
This will result in a dict with subject: time key-value pairs.
The best practice is to make a new list of the entries to delete, and to delete them after walking the list:
to_del = []
subjectlength = 8
for x in range(subjectlength):
for y in range(x):
if subject[x] == subject[y]:
#add
time[x] = time[x] + time[y]
to_del.append(y)
to_del.reverse()
for d in to_del:
del subject[d]
del time[d]
An alternate way would be to create the subject and time lists anew, using a dict to sum up the times of recurring subjects (I am assuming subjects are strings i.e. hashable).
subjects=['math','english','necromancy','philosophy','english','latin','physics','latin']
time=[1,2,3,4,5,6,7,8]
tuples=zip(subjects,time)
my_dict={}
for subject,t in tuples:
try:
my_dict[subject]+=t
except KeyError:
my_dict[subject]=t
subjects,time=my_dict.keys(), my_dict.values()
print subjects,time
Though a while loop is certainly a better choice for this, if you insist on using a for loop, one can replace the list elements-to-be-deleted with None, or any other distinguishable item, and redefine the list after the for loop. The following code removes even elements from a list of integers:
nums = [1, 1, 5, 2, 10, 4, 4, 9, 3, 9]
for i in range(len(nums)):
# select the item that satisfies the condition
if nums[i] % 2 == 0:
# do_something_with_the(item)
nums[i] = None # Not needed anymore, so set it to None
# redefine the list and exclude the None items
nums = [item for item in nums if item is not None]
# num = [1, 1, 5, 9, 3, 9]
In the case of the question in this post:
...
for i in range(subjectlength - 1):
for j in range(i+1, subjectlength):
if subject[i] == subject[j]:
#add
time[i] += time[j]
# set to None instead of delete
time[j] = None
subject[j] = None
time = [item for item in time if item is not None]
subject = [item for item in subject if item is not None]

Categories

Resources