I have the following list of tuples:
a = [(1, 2), (2, 4), (3, 1), (4, 4), (5, 2), (6, 8), (7, -1)]
I would like to select the elements which second value in the tuple is increasing compared to the previous one. For example I would select (2, 4) because 4 is superior to 2, in the same manner I would select (4, 4) and (6, 8).
Can this be done in a more elegant way than a loop starting explicitly on the second element ?
To clarify, I want to select the tuples which second elements are superior to the second element of the prior tuple.
>>> [right for left, right in pairwise(a) if right[1] > left[1]]
[(2, 4), (4, 4), (6, 8)]
Where pairwise is an itertools recipe you can find here.
You can use a list comprehension to do this fairly easily:
a = [a[i] for i in range(1, len(a)) if a[i][1] > a[i-1][1]]
This uses range(1, len(a)) to start from the second element in the list, then compares the second value in each tuple with the second value from the preceding tuple to determine whether it should be in the new list.
Alternatively, you could use zip to generate pairs of neighbouring tuples:
a = [two for one, two in zip(a, a[1:]) if two[1] > one[1]]
You can use enumerate to derive indices and then make list comprehension:
a = [t[1] for t in enumerate(a[1:]) if t[1][1] > a[t[0]-1][1]]
You can use list comprehension
[i for i in a if (i[0] < i[1])]
Returns
[(1, 2), (2, 4), (6, 8)]
Edit: I was incorrect in my understanding of the question. The above code will return all tuples in which the second element is greater than the first. This is not the answer to the question OP asked.
Related
from collections import Counter
test_list = [(6, 5), (2, 7), (2, 5), (8, 7), (9, 8), (3, 7)]
freq_2ndEle=Counter(val for key,val in test_list)
res=sorted(test_list,key=lambda ele:freq_2ndEle[ele[1]],reverse=True)
print(res)
Input : test_list = [(6, 5), (1, 7), (2, 5), (8, 7), (9, 8), (3, 7)]
Output : [(1, 7), (8, 7), (3, 7), (6, 5), (2, 5), (9, 8)]
Explanation : 7 occurs 3 times as 2nd element, hence all tuples with 7, are aligned first.
please clarify how the code is working especially, this part
res=sorted(test_list,key=lambda ele:freq_2ndEle[ele[1]],reverse=True)
I have confusion on ele:freq_2ndEle[ele[1]].
Here is an explanation - in the future, you should try following similar steps, including reading the documentation:
Counter takes an iterable or a map as an argument. In your case, val for key,val in test_list is an iterable. You fetch values from test_list and feed them to Counter.
You don't need the key, val semantics, it is confusing in this context, as it suggests you are looping through a dictionary. Instead, you are looping through a list of tuples so freq_2ndEle=Counter(tp[1] for tp in test_list) is much clearer - here you access the second tuple element, indexed with 1.
Counter gives you number of occurrences of each of the second tuple elements. If you print freq_2ndEle, you will see this:
Counter({7: 3, 5: 2, 8: 1}), which is a pair of how many times each second element appears in the list.
In the last step you're sorting the original list by the frequency of the second element using sorted,
res=sorted(test_list,key=lambda ele:freq_2ndEle[ele[1]],reverse=True)
So you take in test_list as an argument to sort, and then you specify the key by which you want to sort: in your case the key is the the time second tuple element occurred.
freq_2ndEle stores key-value pairs of second second element name:times it ocurred in test_list - it is a dictionary in a way, so you access it as you would access a dictionary, that is - you get the value that corresponds to ele[1] which is the (name) of the second tuple element. Name is not the base term, but I thought it may be clearer. The value you fetch with freq_2ndEle[ele[1]] is exactly the time ele[1] occurred in test_list
Lastly, you sort the keys, but in reverse order - that is, descending, highest to lowest, [(2, 7), (8, 7), (3, 7), (6, 5), (2, 5), (9, 8)] with the values that have the same keys (like 7 and 5) grouped together. Note, according to the documentation sorted is stable, meaning it will preserve the order of elements from input, and this is why when the keys are the same, you get them in the order as in test_list i.e. (2,7) goes first and (3,7) last in the "7" group.
freq_2ndEle is a dictionary that contains the second elements of the tuple as keys, and their frequencies as values. Passing this frequency as a return value of lambda in the key argument of the function sorted will sort the list by this return value of lambda (which is the frequency).
If your question is about how lambda works, you can refer to this brief explanation which is pretty simple.
I have created a class with attributes and sorted them based on their level of x, from 1-6. I then want to sort the list into pairs, where the objects with the highest level of "x" and the object with the lowest level of "x" are paired together, and the second most and second less and so on. If it was my way it would look like this, even though objects are not itereable.
for objects in sortedlist:
i = 0
row(i) = [[sortedlist[i], list[-(i)-1]]
i += 1
if i => len(sortedlist)
break
Using zip
I think the code you want is:
rows = list(zip(sortedList, reversed(sortedList)))
However, note that this would "duplicate" the elements:
>>> sortedList = [1, 2, 3, 4, 5]
>>> list(zip(sortedList, reversed(sortedList)))
[(1, 5), (2, 4), (3, 3), (4, 2), (5, 1)]
If you know that the list has an even number of elements and want to avoid duplicates, you can instead write:
rows = list(zip(sortedList[:len(sortedList)//2], reversed(sortedList[len(sortedList)//2:])))
With the following result:
>>> sortedList = [1,2,3,4,5,6]
>>> list(zip(sortedList[:len(sortedList)//2], reversed(sortedList[len(sortedList)//2:])))
[(1, 6), (2, 5), (3, 4)]
Using loops
Although I recommend using zip rather than a for-loop, here is how to fix the loop you wrote:
rows = []
for i in range(len(sortedList)):
rows.append((sortedList[i], sortedList[-i-1]))
With result:
>>> sortedList=[1,2,3,4,5]
>>> rows = []
>>> for i in range(len(sortedList)):
... rows.append((sortedList[i], sortedList[-i-1]))
...
>>> rows
[(1, 5), (2, 4), (3, 3), (4, 2), (5, 1)]
In python, I wish to sort tuples based on the value of their last element. For example, i have a tuple like the one below.
tuples = [(2,3),(5,7),(4,3,1),(6,3,5),(6,2),(8,9)]
which after sort I wish to be in this format.
tuples = [(4,3,1),(6,2),(2,3),(6,3,5),(5,7),(8,9)]
How do i get to doing that?
Povide list.sort with an appropriate key function that returns the last element of a tuple:
tuples.sort(key=lambda x: x[-1])
You can use:
from operator import itemgetter
tuples = sorted(tuples, key=itemgetter(-1))
The point is that we use key as a function to map the elements on an orderable value we wish to sort on. With itemgetter(-1) we construct a function, that for a value x, will return x[-1], so the last element.
This produces:
>>> sorted(tuples, key=itemgetter(-1))
[(4, 3, 1), (6, 2), (2, 3), (6, 3, 5), (5, 7), (8, 9)]
Given a list l and all combinations of the list elements is it possible to remove any combination containing x while iterating over all combinations, so that you never consider a combination containing x during the iteration after it is removed?
for a, b in itertools.combinations(l, 2):
if some_function(a,b):
remove_any_tup_with_a_or_b(a, b)
My list l is pretty big so I don't want to keep the combinations in memory.
A cheap trick to accomplish this would be to filter by disjoint testing using a dynamically updated set of exclusion values, but it wouldn't actually avoid generating the combinations you wish to exclude, so it's not a major performance benefit (though filtering using a C built-in function like isdisjoint will be faster than Python level if checks with continue statements typically, by pushing the filter work to the C layer):
from future_builtins import filter # Only on Py2, for generator based filter
import itertools
blacklist = set()
for a, b in filter(blacklist.isdisjoint, itertools.combinations(l, 2)):
if some_function(a,b):
blacklist.update((a, b))
If you want to remove all tuples containing the number x from the list of combinations itertools.combinations(l, 2), consider that you there is a one-to-one mapping (mathematically speaking) from the set itertools.combinations([i for i in range(1,len(l)], 2) to the itertools.combinations(l, 2) that don't contain the number x.
Example:
The set of all of combinations from itertools.combinations([1,2,3,4], 2) that don't contain the number 1 is given by [(2, 3), (2, 4), (3, 4)]. Notice that the number of elements in this list is equal to the number of elements of combinations in the list itertools.combinations([1,2,3], 2)=[(1, 2), (1, 3), (2, 3)].
Since order doesn't matter in combinations, you can map 1 to 4 in [(1, 2), (1, 3), (2, 3)] to get [(1, 2), (1, 3), (2, 3)]=[(4, 2), (4, 3), (2, 3)]=[(2, 4), (3, 4), (2, 3)]=[(2, 3), (2, 4), (3, 4)].
Given a list of non-empty tuples, return a list sorted in increasing order by the last element in each tuple.
e.g. [(1, 7), (1, 3), (3, 4, 5), (2, 2)] yields [(2, 2), (1, 3), (3, 4, 5), (1, 7)]
Hint: use a custom key= function to extract the last element form each tuple.
The solution to the problem is:
def last(a):
return a[-1]
def sort_last(tuples):
return sorted(tuples, key=last)
Can anyone help me to understand what arguments are passed to the last function? Specifically, what does a contain?
We have not passed any values or arguments while calling the last function in the sorted method.
This is what is called a "lambda".
It's passing the current element of your list to the function "last" which will then get the last element of the tuple.
So the parameter "a" is the tuple being currently processed.
Iterating through a tuple via for loop - (Sorted initial list with 2nd element of the tuple.)
Nested for loops - comparing original tuple with the sorted 2nd element list.
tuple1 = [(2, 5), (1, 2), (4, 4), (2, 3), (2, 1)]
List2 =[]
List3 =[]
for t in tuple1:
List2.append(t[1],)
List2.sort()
print(List2)
for l in List2:
for q in tuple1:
if l == int(q[1],):
List3.append(q)
print(List3)