Python sorting by multiple criteria - python

I have a list where each element is of the form [list of integers, integer].
For example, an element of the list may look like this [[1,3,1,2], -1].
I want to sort a list containing the described type of elements by the following criteria:
if the integer lists of two elements (i.e. element[0]) are of different length, the element with the smaller integer list is the smaller one.
else if the integer lists are of the same length, the smaller element is that which has the smaller integer for the first integer which differs in the integer list of both elements. For example:
[[1,1,99,100], -1] < [[1,1,100,1], -1], because 99 < 100.
else if the integer lists are identical, the smaller element is the one with the smaller integer in element[1].
How would I write an approriate key function I could pass to sorted() or sort()?

List the three criteria in your key:
sorted(inputlist, key=lambda e: (len(e[0]), e[0], e[1]))
Now you are sorting each element first by the length, then by comparing the first element directly (which in only used when the first element is of equal length), then by the value of the last integer.
Python sorts tuples and lists like these lexicographically; compare the first element, and only if that doesn't differ, compare the second element, etc.
The second element here is e[0] which will only be used if both compared entries have nested lists of equal length. These are again compared lexicographically, so pairing up elements until a pair differs.

key = lambda x: (len(x[0]), x[0], x[1])
This works because tuples (and lists) are compared by looking at each element in turn until a difference is found. So when you want to sort on multiple criteria in order of preference, just stick each criterion into an element of a tuple, in the same order.
I'm assuming that by "smaller" you mean the same thing as "lesser", that is to say you don't mean to compare absolute values.

Related

How do I sort this list of lists in that matches two conditions? [duplicate]

I have a list where each element is of the form [list of integers, integer].
For example, an element of the list may look like this [[1,3,1,2], -1].
I want to sort a list containing the described type of elements by the following criteria:
if the integer lists of two elements (i.e. element[0]) are of different length, the element with the smaller integer list is the smaller one.
else if the integer lists are of the same length, the smaller element is that which has the smaller integer for the first integer which differs in the integer list of both elements. For example:
[[1,1,99,100], -1] < [[1,1,100,1], -1], because 99 < 100.
else if the integer lists are identical, the smaller element is the one with the smaller integer in element[1].
How would I write an approriate key function I could pass to sorted() or sort()?
List the three criteria in your key:
sorted(inputlist, key=lambda e: (len(e[0]), e[0], e[1]))
Now you are sorting each element first by the length, then by comparing the first element directly (which in only used when the first element is of equal length), then by the value of the last integer.
Python sorts tuples and lists like these lexicographically; compare the first element, and only if that doesn't differ, compare the second element, etc.
The second element here is e[0] which will only be used if both compared entries have nested lists of equal length. These are again compared lexicographically, so pairing up elements until a pair differs.
key = lambda x: (len(x[0]), x[0], x[1])
This works because tuples (and lists) are compared by looking at each element in turn until a difference is found. So when you want to sort on multiple criteria in order of preference, just stick each criterion into an element of a tuple, in the same order.
I'm assuming that by "smaller" you mean the same thing as "lesser", that is to say you don't mean to compare absolute values.

How can I sum pairs of numbers in a list and if the sum is equal to another element in the list, how can I remove this element from the list?

I have a list of numbers:
nums = [-3,-2,-1,1,2,3,0,0]
And I want to iterate over the list, and add two numbers at a time, and if the sum of these two numbers is an element in the list (excluding the two we just summed), then I want to remove the element. How can I do this?
For example, since -3+2= -1 and -1 is in the list, I can remove -1 from the list.
I tried to create an empty list/set to store the sums of each pair of elements, then compare the elements in nums to this list/set, but this doesn't work, as it violates the second part of what I want to do- in brackets above!
P.S. I would like to remove as many elements as possible, and one worry is that if I remove elements as I iterate the list- before finding all of the pair sums- then I might miss some valid pair sums!
Any help is much appreciated.
Although possibly inefficient (didn't care about efficiency when writing this answer), you could probably do the following:
for first in nums[:]:
if first == 0: continue
for second in nums[:]:
if second == 0: continue
sum = first + second
if sum in nums:
nums.remove(sum)
There are 2 things I will go over in this answer;
nums[:] is the slicing syntax that will just create a copy of the array, whereafter that copy will be iterated over. The syntax for this was found within this answer: https://stackoverflow.com/a/1207461/6586516
There are also checks to see if either the first or second number is equal to 0. This will satisfy the second condition (according to my logic). The only time the sum of a set of numbers can be equal to itself/one of the numbers used in the addition is when n - 1 numbers is equal to 0 (where n is the amount of numbers used in the addition)
You could try something like this:
itertools.combinations returns us with all possible combinations of a the argument. Since you want to numbers, providing 2 as the argument will return all possible combinations with length 2
Then we will just check the conditions and proceed to remove from the list.
from itertools import combinations
nums = [-3,-2,-1,1,2,3,0,0]
nums2=[i for i in combinations(nums,2)]
print(nums2)
for i in nums2:
sums=i[0]+i[1]
if sums in nums and (sums!=i[0] and sums!=i[1]):
try:
print(f"{sums} removed from list.\nNew List: {nums}")
nums.remove(sums)
except ValueError:
print("{sums} not in list")
print(nums)

min on Python tuple with zeros [duplicate]

I have been reading the Core Python programming book, and the author shows an example like:
(4, 5) < (3, 5) # Equals false
So, I'm wondering, how/why does it equal false? How does python compare these two tuples?
Btw, it's not explained in the book.
Tuples are compared position by position:
the first item of the first tuple is compared to the first item of the second tuple; if they are not equal (i.e. the first is greater or smaller than the second) then that's the result of the comparison, else the second item is considered, then the third and so on.
See Common Sequence Operations:
Sequences of the same type also support comparisons. 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.
Also Value Comparisons for further details:
Lexicographical comparison between built-in collections works as follows:
For two collections to compare equal, they must be of the same type, have the same length, and each pair of corresponding elements must compare equal (for example, [1,2] == (1,2) is false because the type is not the same).
Collections that support order comparison are ordered the same as their first unequal elements (for example, [1,2,x] <= [1,2,y] has the same value as x <= y). If a corresponding element does not exist, the shorter collection is ordered first (for example, [1,2] < [1,2,3] is true).
If not equal, the sequences are ordered the same as their first differing elements. For example, cmp([1,2,x], [1,2,y]) returns the same as cmp(x,y). If the corresponding element does not exist, the shorter sequence is considered smaller (for example, [1,2] < [1,2,3] returns True).
Note 1: < and > do not mean "smaller than" and "greater than" but "is before" and "is after": so (0, 1) "is before" (1, 0).
Note 2: tuples must not be considered as vectors in a n-dimensional space, compared according to their length.
Note 3: referring to question https://stackoverflow.com/questions/36911617/python-2-tuple-comparison: do not think that a tuple is "greater" than another only if any element of the first is greater than the corresponding one in the second.
The Python documentation does explain it.
Tuples and lists are compared
lexicographically using comparison of
corresponding elements. This means
that to compare equal, each element
must compare equal and the two
sequences must be of the same type and
have the same length.
The python 2.5 documentation explains it well.
Tuples and lists are compared lexicographically using comparison of corresponding elements. This means that to compare equal, each element must compare equal and the two sequences must be of the same type and have the same length.
If not equal, the sequences are ordered the same as their first differing elements. For example, cmp([1,2,x], [1,2,y]) returns the same as cmp(x,y). If the corresponding element does not exist, the shorter sequence is ordered first (for example, [1,2] < [1,2,3]).
Unfortunately that page seems to have disappeared in the documentation for more recent versions.
I had some confusion before regarding integer comparsion, so I will explain it to be more beginner friendly with an example
a = ('A','B','C') # see it as the string "ABC"
b = ('A','B','D')
A is converted to its corresponding ASCII ord('A') #65 same for other elements
So,
>> a>b # True
you can think of it as comparing between string (It is exactly, actually)
the same thing goes for integers too.
x = (1,2,2) # see it the string "123"
y = (1,2,3)
x > y # False
because (1 is not greater than 1, move to the next, 2 is not greater than 2, move to the next 2 is less than three -lexicographically -)
The key point is mentioned in the answer above
think of it as an element is before another alphabetically not element is greater than an element and in this case consider all the tuple elements as one string.

Short code and notation in python

I see some codes like this:
K = np.array([B[z==i].mean(axis=0) for i in range(k)])
Where B is a 2D array (matrix) and z is a 1D array (vector).
I am wondering what B[z==i] means?
In B[z==i] you have two types of operations.
First, given B[i] for i in range(k) what are you doing in cases like this is an iteration over the values of the list B.
In your case you have z==i which is a comparison between objects.
In python the objects to compare does not need to have the same type, but if the types are different, they always return False.
A little summary of how comparisons work:
Numbers are compared arithmetically.
Strings are compared lexicographically using the numeric equivalents
(the result of the built-in function ord()) of their characters.
Unicode and 8-bit strings are fully interoperable in this behavior.
Tuples and lists are compared lexicographically using comparison of
corresponding elements. This means that to compare equal, each element
must compare equal and the two sequences must be of the same type and
have the same length.
If not equal, the sequences are ordered the same as their first
differing elements. For example, cmp([1,2,x], [1,2,y]) returns the
same as cmp(x,y). If the corresponding element does not exist, the
shorter sequence is ordered first (for example, [1,2] < [1,2,3]).
Mappings (dictionaries) compare equal if and only if their sorted
(key, value) lists compare equal.5.3Outcomes other than equality are
resolved consistently, but are not otherwise defined.
Most other types compare unequal unless they are the same object; the
choice whether one object is considered smaller or larger than another
one is made arbitrarily but consistently within one execution of a
program.
This document is a little bit old but you can have more information about comparisons there: source

Indices of cross-referenced lists

I'm cross-referencing two lists to find which items coincide between the two lists. The first list orig is 32 items in size, and I'm cross-referencing it with a much-larger list sdss which is 112,000 items in size. So far this is what I've got:
for i in range(0,len(orig),1):
if orig[i] in sdss:
print('\n %s' % (orig[i]))
This gives me the items that are the same between the two lists, however, how would I efficiently return the indices (or location) of cross-referenced items inside of the sdss list (the larger list)?
EDIT: I guess I should've been clearer. I am actually cross-referencing two arrays with ints, not strings.
If the order is not of importance you can use set intersection to find the unique common elements and list comprehension to get the index and element as tuple
[(sdss.index(common_element),common_element) for common_element in set(orig) & set(sdss)]
Note that "index" raises ValueError if the value is not found in the list but in this case the value WILL exist in sdss. So, no need to worry about nonexistent elements throwing errors.
You can also use numpy.intersect1d
You can use .find() which gives the index of an item in a list, but returns -1 on failure:
for item in orig:
index = sdss.find(item)
if index != -1:
print("\n %d" % index)
I modified how you iterated because you don't need the index in orig; you need each item. BTW, you could have used range(len(orig)) because your start and step arguments are already the defaults.

Categories