Related
I'd like to make a recursive algorithm generating all permutations of a list of integers taken k things at a time.
To be specific, what I want to do is create a recursive function Perm(list, k) from scratch returning a output satisfying the following condition.
from itertools import permutations
li = [1,2,3,4]
set(permutations(li, 2)) == set(Perm(li, 2))
I tried it by referring to the Shailaja's codes (Perm(lst,n)) from this link: Recursive Algorithm to generate all permutations of length k of a list in Python
Since the function returns a nested list, I've tried to convert the nested list to a set of tuples. However, I was unable to find any solutions because the function is a recursive algorithm. Could anyone help me out to change the Perm function to get the following format of outputs? Thanks a lot.
# the output of set(Perm(li, 2))
{(1, 2),
(1, 3),
(1, 4),
(2, 1),
(2, 3),
(2, 4),
(3, 1),
(3, 2),
(3, 4),
(4, 1),
(4, 2),
(4, 3)}
Since the function returns a nested list, I've tried to convert the nested list to a set of tuples.
Yes, that is indeed what is needed. So Perm should yield tuples.
Here is a possible recursive implementation for Perm:
def Perm(lst, size):
if size <= 0:
yield () # empty tuple
else:
for i, val in enumerate(lst):
for p in Perm(lst[:i] + lst[i+1:], size-1):
yield (val, *p)
This passes the test given in the question.
all I have a list of list of tuple here
A =[[(1, 52), (1, 12), (-1, -1)],[(-1, 23), (1, 42), (-1, -1)],[(1, -1), (-1, -1), (1, 42)]]
I wanted get the tuples containing the max values in second element of the tuple, column-wise.
I tried accessing columns like this
A[:,2]
But I get the error
TypeError: list indices must be integers, not tuple
Thanks in advance, Please let me know if you need any other information
Edit 1:
Desired output:
[(1, 52),(1, 42),(1, 42)]
[max(a,key=lambda x:x[1]) for a in zip(*A)]
output:
[(1, 52), (1, 42), (1, 42)]
Let me know if this works for you I will explain the answer.
You can access columns like this..
>>> list(zip(*A)[0])
[(1, 52), (-1, 23), (1, -1)]
>>> list(zip(*A)[1])
[(1, 12), (1, 42), (-1, -1)]
Explanation
zip https://docs.python.org/3/library/functions.html#zip
>>> x=[1,2,3]
>>> y=['a','b','c']
>>> z=['first','second','third']
>>> zip(x,y,z)
[(1, 'a', 'first'), (2, 'b', 'second'), (3, 'c', 'third')]
Now imagine x,y,z being the rows you had in A. By zip(rows) it returns 1st elements, 2nd elements, 3rd elements etc... There by returning us columns of the rows we passed.
Note: zip acts on multiple arguments passed in so we need to send multiple rows like x,y,z separately, not like [x,y,z] as a list. That is done by *A which separates the rows and passes to zip.
Now we got different columns
maxhttps://docs.python.org/3/library/functions.html#max
max(1,2) #Will return 2
max(cars,lambda x:x.speed) #Will give you the fastest car
max(cars,lambda x:x.capacity) #Will give you the biggest passenger car
max(tups,lambda x:x[1]) #Will give you the tuple with biggest 2nd element
List Comprehensionhttps://docs.python.org/3/tutorial/datastructures.html#list-comprehensions
A=[1,2,3]
[x**2 for x in A] #Will give you [1,4,9]
[x**3 for x in A] #Will give you [1,8,27]
Finally
[max(a,key=lambda x:x[1]) for a in zip(*A)]
Will give you max for each column!
You can try this:
A =[[(1, 52), (1, 12), (-1, -1)],[(-1, 23), (1, 42), (-1, -1)],[(1, -1), (-1, -1), (1, 42)]]
new_A = [max(a, key=lambda x: x[-1]) for a in zip(*A)]
Output:
[(1, 52), (1, 42), (1, 42)]
A is a list is lists of tuples. Basic Python does not recognised multiple-element subscripting, although Numpy and similar modules extend it. Your subscript expression :,2 is therefore interpreted as a tuple whose first element is a lice and whose second element is an integer, which (as the message explains) is not acceptable as a list index.
Unfortunately, "the tuples containing the max values in second element of the tuple, column-wise" isn't a terribly good description of the actual desired result.
I presume the answer you would like is [(1, 52), (1, 42), (1, 42)].
One relatively simple way to achieve this is to sort each of the sub-lists separately, taking the last element of each. this could be spelled as
result = [sorted(x, key=lambda z: z[1])[-1] for x in A]
The key argument to the sorted function ensures that each list is sorted on its second element, the
[-1] subscript takes the last (and therefore highest) element of the sorted list, and the for x in A ensure that each element of the output corresponds to an element (i.e., a list of three tuples) of the input.
Summary
Sorting in Python is guaranteed to be stable since Python 2.2, as documented here and here.
Wikipedia explains what the property of being stable means for the behavior of the algorithm:
A sorting algorithm is stable if whenever there are two records R and S with the same key, and R appears before S in the original list, then R will always appear before S in the sorted list.
However, when sorting objects, such as tuples, sorting appears to be unstable.
For example,
>>> a = [(1, 3), (3, 2), (2, 4), (1, 2)]
>>> sorted(a)
[(1, 2), (1, 3), (2, 4), (3, 2)]
However, to be considered stable, I thought the new sequence should've been
[(1, 3), (1, 2), (2, 4), (3, 2)]
because, in the original sequence, the tuple (1, 3) appears before tuple (1, 2). The sorted function is relying on the 2-ary "keys" when the 1-ary "keys" are equal. (To clarify, the 1-ary key of some tuple t would be t[0] and the 2-ary t[1].)
To produce the expected result, we have to do the following:
>>> sorted(a, key=lambda t: t[0])
[(1, 3), (1, 2), (2, 4), (3, 2)]
I'm guessing there's a false assumption on my part, either about sorted or maybe on how tuple and/or list types are treated during comparison.
Questions
Why is the sorted function said to be "stable" even though it alters the original sequence in this manner?
Wouldn't setting the default behavior to that of the lambda version be more consistent with what "stable" means? Why is it not set this way?
Is this behavior simply a side-effect of how tuples and/or lists are inherently compared (i.e. the false assumption)?
Thanks.
Please note that this is not about whether the default behavior is or isn't useful, common, or something else. It's about whether the default behavior is consistent with the definition of what it means to be stable (which, IMHO, does not appear to be the case) and the guarantee of stability mentioned in the docs.
Think about it - (1, 2) comes before (1, 3), does it not? Sorting a list by default does not automatically mean "just sort it based off the first element". Otherwise you could say that apple comes before aardvark in the alphabet. In other words, this has nothing to do with stability.
The docs also have a nice explanation about how data structures such as lists and tuples are sorted lexicographically:
In particular, tuples and lists are compared lexicographically by comparing corresponding elements. This means that to compare equal, every element must compare equal and the two sequences must be of the same type and have the same length.
Stable sort keeps the order of those elements which are considered equal from the sorting point of view. Because tuples are compared element by element lexicographically, (1, 2) precedes (1, 3), so it should go first:
>>> (1, 2) < (1, 3)
True
A tuple's key is made out of all of its items.
>>> (1,2) < (1,3)
True
I have a list of tuples, each tuple contains two integers. I need to sort the the list (in reverse order) according to the difference of the integers in each tuple, but break ties with the larger first integer.
Example
For [(5, 6), (4, 1), (6, 7)], we should get [(4, 1), (6, 7), (5, 6)].
My way
I have already solved it by making a dictionary that contains the difference as the key and the tuple as the value. But the whole thing is a bit clumsy.
What is a better way?
Use a key function to sorted() and return a tuple; values will be sorted lexicographically:
sorted(yourlst, key=lambda t: (abs(t[0] - t[1])), t[0]), reverse=True)
I'm using abs() here to calculate a difference, regardless of which of the two integers is larger.
For your sample input, the key produces (1, 5), (3, 4) and (1, 6); in reverse order that puts (1, 6) (for the (6, 7) tuple) before (1, 5) (corresponding with (5, 6)).
Demo:
>>> yourlst = [(5, 6), (4, 1), (6, 7)]
>>> sorted(yourlst, key=lambda t: (abs(t[0] - t[1]), t[0]), reverse=True)
[(4, 1), (6, 7), (5, 6)]
Given this list=[('a','b',3),('d','e',3),('e','f',5)], if you'd like to sort by the number in descending order, but break ties (when counts are equal like with the '3' on this example) using ascending alphabetical order of the first element and then the second element repectively, the following code works:
sorted(list,key=lambda x: (-x[2],x[0],x[1]))
Here the '-' sign on the x[2] indicates it needs to be sorted in the descending order.
The output will be: [('e', 'f', 5), ('a', 'b', 3), ('d', 'e', 3)]
While working on a problem from Google Python class, I formulated following result by using 2-3 examples from Stack overflow-
def sort_last(tuples):
return [b for a,b in sorted((tup[1], tup) for tup in tuples)]
print sort_last([(1, 3), (3, 2), (2, 1)])
I learned List comprehension yesterday, so know a little about list comprehension but I am confused how this solution is working overall. Please help me to understand this (2nd line in function).
That pattern is called decorate-sort-undecorate.
You turn each (1, 3) into (3, (1, 3)), wrapping each tuple in a new tuple, with the item you want to sort by first.
You sort, with the outer tuple ensuring that the second item in the original tuple is sorted on first.
You go back from (3, (1, 3)) to (1, 3) while maintaining the order of the list.
In Python, explicitly decorating is almost always unnecessary. Instead, use the key argument of sorted:
sorted(list_of_tuples, key=lambda tup: tup[1]) # or key=operator.itemgetter(1)
Or, if you want to sort on the reversed version of the tuple, no matter its length:
sorted(list_of_tuples, key=lambda tup: tup[::-1])
# or key=operator.itemgetter(slice(None, None, -1))
Lets break it down:
In : [(tup[1],tup) for tup in tuples]
Out: [(3, (1, 3)), (2, (3, 2)), (1, (2, 1))]
So we just created new tuple where its first value is the last value of inner tuple - this way it is sorted by the 2nd value of each tuple in 'tuples'.
Now we sort the returned list:
In: sorted([(3, (1, 3)), (2, (3, 2)), (1, (2, 1))])
Out: [(1, (2, 1)), (2, (3, 2)), (3, (1, 3))]
So we now have our list sorted by its 2nd value of each tuple. All that is remain is to extract the original tuple, and this is done by taking only b from the for loop.
The list comprehension iterates the given list (sorted([...] in this case) and returns the extracted values by order.
Your example works by creating a new list with the element at index 1 followed by the original tuple for each tuple in the list. Eg. (3,(1,3)) for the first element. The sorted function sorts by each element starting from index 0 so the list is sorted by the second item. The function then goes through each item in the new list, and returns the orignal tuples.
Another way of doing this is by using the key parameter in the sorted function which sorts based on the value of the key. In this case you want the key to be the item in each tuple at index 1.
>>> from operator import itemgetter
>>> sorted([(1, 3), (3, 2), (2, 1)],key=itemgetter(1))
Pls refer to the accepted answer.. + here is an example for better visualization,
key is a function that will be called to transform the collection's items for comparison.. like compareTo method in Java.
The parameter passed to key must be something that is callable. Here, the use of lambda creates an anonymous function (which is a callable).
The syntax of lambda is the word lambda followed by a iterable name then a single block of code.
Below example, we are sorting a list of tuple that holds the info abt time of certain event and actor name.
We are sorting this list by time of event occurrence - which is the 0th element of a tuple.
Shout out for the Ready Player One fans! =)
>>> gunters = [('2044-04-05', 'parzival'), ('2044-04-07', 'aech'), ('2044-04-06', 'art3mis')]
>>> gunters.sort(key=lambda tup: tup[0])
>>> print gunters
[('2044-04-05', 'parzival'), ('2044-04-06', 'art3mis'), ('2044-04-07', 'aech')]
Note - s.sort([cmp[, key[, reverse]]]) sorts the items of s in place