Sorting lists of floats - python-3.x

I would like to sort the list s and in the same manner the list s1. The code below workers for integers (after changing 2.2 to 2 and 20.6 to 20). How to adjust the code for floats, please?
s = [2.2, 3, 1, 4, 5, 3]
s1 = [20.6, 600, 10, 40, 5000, 300]
res = []
for i in range(len(s1)):
res0 = s1[s[i]]
res.append(res0)
print(res)
print('Sorted s:', sorted(s))
print('Ind:', sorted(range(len(s)), key=lambda k: s[k]))
print('s1 in the same manner as s:', res)

There is actually an error related with a part of your code res0 = s1[s[i]] that pops up:
list indices must be integers or slices, not float.
Supposed that the index is 0: s1[s[0]] -> s[0] == 2.2 -> s1[2.2]
Your code is actually using the values of s as an index for each value of s1. Your code wouldn't be able to sort a list by the manner of another list regardless if the list contains integers only.
Instead, you should add two new arrays:
s_index_list = sorted(range(len(s)), key=lambda k: s[k])
s1_sorted = sorted(s1)
One which contains the index of each value of s (Reference to this answer https://stackoverflow.com/a/7851166/18052186), and another which sort s1.
Then, you replace this bit of your code.
res0 = s1[s[i]]
by
res0 = s1_sorted[s_index_list[i]]
That way, you can sort the list s1 in the same manner as s by actually associating a value of s1 with an index from s. The result would have been:
[40, 10, 20.6, 5000, 300, 600]
Sorted s: [1, 2.2, 3, 3, 4, 5]
Ind: [2, 0, 1, 5, 3, 4]
s1 in the same manner as s: [40, 10, 20.6, 5000, 300, 600]

Related

LIS on two arrays

I feel lost on how to approach this question,
Given two integer array of size 𝑛
, 𝑚
, I want to merge these two arrays into one such that order of element in each array doesn't change and size of their Longest Increasing Subsequence become maximum.
Once we choose an element of A or B, we cannot choose an earlier element of that sequence
My goal is to find maximum possible length of longest increasing subsequence.
This is what I have so far:
def sequences(a, b, start_index=0, min_val=None):
limits = a[start_index], b[start_index]
lower = min(limits)
higher = max(limits)
if min_val is not None and min_val > lower:
lower = min_val
options = range(lower, higher + 1)
is_last = start_index == len(a) - 1
for val in options:
if is_last:
yield [val]
else:
for seq in sequences(a, b, start_index+1, min_val=val+1):
yield [val, *seq]
for seq in sequences([1,3,1,6], [6,5,4,4]):
print(seq)
However, this results in: [1, 3, 4, 5], [1, 3, 4, 6], [2, 3, 4, 5], [2, 3, 4, 6].
The expected output should be:
array1: [1,3,1,6]
array2: [6,5,4,4]
We take 1(from array1), 3(from array1), 4(from array2), 6(from array1)
Giving us LIS: [1,3,4,6].
We got this by not choosing an earlier element from a sequence once we are at a certain value.
How do I stop it from unwanted recursion?

Reverse operation of torch.unique

In pytorch , unique (with return_count is True) operation do like this
[1,1,2,2,3,3] => ([1,2,3],[2,2,2])
Are there any reverse operations of torch.unique() ?
i.e Given a unique list and its count , return the original list like
([1,2,3],[2,2,2]) = > [1,1,2,2,3,3]
If you include the return inverse parameter it will return the indices for where elements in the original input ended up in the returned unique list. Then you can use take to create a new tensor.
test_tensor = torch.tensor([1,1,2,2,3,3])
items, inverse, counts = test_tensor.unique(return_counts=True, return_inverse=True)
new_tensor = torch.take(items, inverse)
assert new_tensor.eq(test_tensor).all() # true
EDIT:
If you only have a list and the counts this code should give you what you want using repeat. Not sure if a pure pytorch function exists.
test_tensor = torch.tensor([1,1,2,2,3,3])
items, counts = test_tensor.unique(return_counts=True)
new_tensor = torch.tensor([], dtype=torch.int64)
for item, count in zip(items, counts):
new_tensor = torch.cat((new_tensor, item.repeat(count)))
assert new_tensor.eq(test_tensor).all() # true
You probably want torch.repeat_interleave(). You can use it like this:
>>> x = torch.tensor([1, 1, 2, 3, 3, 3])
>>> v, c = torch.unique(x, return_counts=True)
>>> v, c
(tensor([1, 2, 3]), tensor([2, 1, 3]))
>>> torch.repeat_interleave(v, c)
tensor([1, 1, 2, 3, 3, 3])

Is it possible to chain iterators on a list in Python?

I have a list with negative and positive numbers:
a = [10, -5, 30, -23, 9]
And I want to get two lists of tuples of the values and their indexes in the original list so I did this.
b = list(enumerate(a))
positive = list(filter(lambda x: x[1] > 0, b))
negative = list(filter(lambda x: x[1] < 0, b))
But it feels kind of bad casting to list in between. Is there a way to chain these iterators immediately?
The iterator returned by enumerate can only be iterated once so that is why you have to cast it to a list or a tuple if you want to reuse the functionality of it multiple times.
If you don't want to cast it or find that looping over the list twice is too inefficient for your liking you might want to consider a standard for loop, since it allows you to append to both lists at the same time in only a single iteration of the original list:
a = [10, -5, 30, -23, 9]
positive, negative = [], []
for idx, val in enumerate(a):
if val == 0:
continue
(positive if val > 0 else negative).append((idx, val))
print(f"Positive: {positive}")
print(f"Negative: {negative}")
Output:
Positive: [(0, 10), (2, 30), (4, 9)]
Negative: [(1, -5), (3, -23)]

Python: Is it possible to do the same using reduce()?

This is part of an assaigment so it needs to be donde using the reduce function (or filter although I don't see it), hence I'd like to know if it's possible.
I have two dicts:
takeOff_Airport = {'LPPD': 4, 'DAAS': 1, 'EDDH': 16, 'LFLL': 17, 'LFPO': 30}
landing_Airport = {'LFPO': 12, 'LPPD': 7, 'UUEE': 11, 'DAAS': 7, 'LFSL': 1}
After applying the follwing code:
airports = (sorted([[k, [v1+landing_Airport[k], v1,landing_Airport[k]]] for k,
v1 in takeOff_Airport.items() if k in landing_Airport],
key=lambda kv:kv[1], reverse=True))
I get the expected result:
airports: [['LFPO', 42, 30, 12], ['LPPD', 11, 4, 7], ['DAAS', 8, 1, 7]]
What 'airports' is printing is a list of lists with the common airport names in both dictionaries (landing and takeoff) and adding the sum of each dict value as well as each of the dictionaries [key:value ].
Is it possible to implement the above using some lambda expression in a reduce function? Maybe in a filter?
It is definitely possible.
The lambda takes as arguments the array x which aggregates the result and the key into one of the airports dictionaries (takeOff_Airport in my example).
If the key exists in the other airport dictionary, then the element formed by [key, sum of each dict value, takeOff value, landing value] is added to the array x. Else, array x is left unchanged.
Pass the lambda into the reduce function, setting the initial value of x to an empty array and it will generate the desired result.
airports = reduce(lambda x, key : x + [[key, takeOff_Airport[key] + landing_Airport[key], takeOff_Airport[key], landing_Airport[key]]] if key in landing_Airport else x, takeOff_Airport, [])
Result:
>>> airports
[['LPPD', 11, 4, 7], ['DAAS', 8, 1, 7], ['LFPO', 42, 30, 12]]

How do I multiply elements in a list and find the sum in a simple way without numpy, zip etc

I have to multiply the same index of two lists and then find the sum of that.
Please help me out! Thank you.
Try this,
>>> A=[2, 3, -6, 7, 10, 11]
>>> B=[1, 2, 3, 4, 5, 6]
>>> sum([x * y for x, y in zip(A, B)])
134
Let me explain what I did in my answer, I used zip() python Built-in Function and this is what documentation mention about it.
Make an iterator that aggregates elements from each of the iterables.
Returns an iterator of tuples, where the i-th tuple contains the i-th element from each of the argument sequences or iterables. The iterator stops when the shortest input iterable is exhausted. With a single iterable argument, it returns an iterator of 1-tuples. With no arguments, it returns an empty iterator.
Little bit confusing, right? Check the below example:-
>>> A=[2, 3, -6, 7, 10, 11]
>>> B=[1, 2, 3, 4, 5, 6]
>>> zip(A,B)
<zip at 0x1fde73e6f88> # it display something like this (zip object)
>>> list(zip(A,B)) # for visualization purpose, convert zip object to list
[(2, 1), (3, 2), (-6, 3), (7, 4), (10, 5), (11, 6)]
I think you can get clear idea what happen inside zip() function. Then multiply each and every value in zip object using python List Comprehensions to answer your question more pythonic. So zip object now created for us a new value series using A and B list. We assigned those values for x and y, multiply them and save in list.
>>> [x * y for x, y in zip(A, B)]
[2, 6, -18, 28, 50, 66]
After all the steps we used sum() to calculate the Sum a list of numbers in Python.
>>> sum([2, 6, -18, 28, 50, 66])
134
That's all, if you didn't get anything please add a comment to this answer.
AB = [A[i] * B[i] for i in range(len(A))]
sum(AB)
Alternatively, try
AB = [value_ * B[i] for i, value_ in enumerate(A)]
sum(AB)
I believe you want this:
def lists(A,B):
C = 0
for i in range(len(A)):
C += (A[i] * B[i])
return C
Now you can call your method lists with lists A and B like this:
A=[2, 3, -6, 7, 10, 11]
B=[1, 2, 3, 4, 5, 6]
lists(A,B)
Which will return 134. Your code was wrong because of your indentation. You had put your return statement inside the for loop, so your code would return C value in the first iteration, which was 0 + 2*1.
with list comprehension:
A = [2, 3, -6, 7, 10, 11]
B = [1, 2, 3, 4, 5, 6]
print (sum([A[i]*B[i] for i in range(len(A))]))
output:
134
your code:
def lists(A, B):
C = 0
for i in range(len(A)):
C += (A[i] * B[i])
return C # <-----
A = [2, 3, -6, 7, 10, 11]
B = [1, 2, 3, 4, 5, 6]
print (lists(A,B))
NOTE: you need to put your return statement out of the for loop.
If return statement is reached during the execution of a function, it will exit from function, what does it mean in your case if you have return in your for loop, in first iteration return function will be reached and exit (you got result 2 because in first iteration yuo have 2*1)

Resources