Python: Is it possible to do the same using reduce()? - python-3.x

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]]

Related

How can I get multiple output variables into a list?

I'm wondering if there's a way of getting multiple outputs from a function into a list. I'm not interested in creating a list inside of a function for reasons I'm not going to waste your time going into.
I know how many output variables I am expecting, but only through using the annotations["return"] expression (or whatever you call that, sorry for the noobish terminology) and this changes from case to case, which is why I need this to be dynamic.
I know I can use lists as multiple variables using function(*myList), but I'm interested in if there's a way of doing the equivalent when receiving return values from a function.
Cheers!
Pseudocode:
function():
x = 1
y = 2
return x, y
variables = function()
print(variables[0], " and ", variables[1]
result should be = "1 and 2"
yes, with the unpacking assignments expression ex a,b,c= myfunction(...), you can put * in one of those to make it take a variable number of arguments
>>> a,b,c=range(3) #if you know that the thing contains exactly 3 elements you can do this
>>> a,b,c
(0, 1, 2)
>>> a,b,*c=range(10) #for when you know that there at least 2 or more the first 2 will be in a and b, and whatever else in c which will be a list
>>> a,b,c
(0, 1, [2, 3, 4, 5, 6, 7, 8, 9])
>>> a,*b,c=range(10)
>>> a,b,c
(0, [1, 2, 3, 4, 5, 6, 7, 8], 9)
>>> *a,b,c=range(10)
>>> a,b,c
([0, 1, 2, 3, 4, 5, 6, 7], 8, 9)
>>>
additionally you can return from a function whatever you want, a list, a tuple, a dict, etc, but only one thing
>>> def fun():
return 1,"boo",[1,2,3],{1:10,3:23}
>>> fun()
(1, 'boo', [1, 2, 3], {1: 10, 3: 23})
>>>
in this example it return a tuple with all that stuff because , is the tuple constructor, so it make a tuple first (your one thing) and return it

Sorting lists of floats

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]

Python - Invert list order

I want to invert list order without changing the values.
The original list is the following:
[15, 15, 10, 8, 73, 1]
While the resulting expecting list is:
[10, 8, 15, 15, 1, 73]
The example has been taken from a real data handling problem from a more complex pandas data frame.
I proposed a list problem only to simplify the issue. So, it can also be a pandas function.
zlist = int(len(list)/2)
for i in range(0, zlist):
a, b = list.index(sorted(list, reverse=True)[i]), list.index(sorted(list,reverse=False)[i])
list[b], list[a] = list[a], list[b]

How to replace every element in a given list to its square and not create a new list with the squares

I want to make a function that takes a list of integers and replaces the elements in the list with their respective squares.
I tried reassigning every element by virtue of its position (index) in the list, but for some reason the second element in the list gets squared twice.
def square_list(list1):
for i in list1:
list1[list1.index(i)] = i**2
print(list1)
square_list([1, 2, 3, 4, 5])
I expect the printed list to be [1, 4, 9, 16, 25] since the list I'm testing the function with is [1, 2, 3, 4, 5].
If a function is required to square list elements in-place, use it:
def square_list(list_1):
for i in range(len(list_1)):
list_1[i] = list_1[i]**2
my_list = [1, 2, 3, 4, 5]
square_list(my_list)
print(my_list)
Since the function doesn't return anything, square_list([1, 2, 3, 4, 5]) is useless.
Python's map built-in function is good for this, so you don't really have to write your own function.
l = [1, 2, 3, 4, 5]
l = list(map(lambda x: x**2, l))

How to find all numbers in a list that are not part of a pair - using python 3

I am trying to write a python 3 function that finds all numbers in a list (unspecified length) that are not part of a pair.
For example, given the list [1, 2, 1, 3, 2], the function will return 3; and given the list [0, 1, 1, 7, 8, 3, 9, 3, 9], the function will return 0, 7, and 8.
Thanks for your help!
You can use the following function :
>>> def find(l):
... return (i for i in l if l.count(i)==1)
>>> l= [0, 1, 1, 7, 8, 3, 9, 3, 9]
>>> list(find(l))
[0, 7, 8]
This function will return a generator that is contain the elements in list which those count is equal to 1.
I can tell you how I would do it. What does it mean a "pair"?
You should say, find all the numbers repeated oddly in the array.
First plan: (more efficient!)
Sort the list and then a single loop through your list should be enough to find how many numbers of each there are inside and you can generate awhile another list that you will return.
Second plan (nicer in python, but also more expensive because of the number of evaluations though the hole list):
Try the solution of Kasra. 'count' function from 'list' type helps our code but not our efficiency. It counts the number of times that appears the value 'i' on the list 'l', obviously.
If the pair need to be "closed pair" I mean, if you have three 1 (ones), do you have one pair and one single 1? or do you have all the 1 paired? If the second one, the solution of Kasra is Ok. Else you should compare:
if l.count(i) % 2 == 1
This can be easily and efficiently done in 3 lines with collections.Counter.
from collections import Counter
def unpaired(numbers):
for key, count in Counter(numbers).items():
if count % 2:
yield key
print(list(unpaired([1, 2, 1, 3, 2])))
# [3]
print(list(unpaired([0, 1, 1, 7, 8, 3, 9, 3, 9])))
# [0, 7, 8]
My answer comport if you have three equals numbers or if you have one pair and one single number without pair.
def name(array):
o = sorted(array)
c = []
d = []
for i in o:
if o.count(i) % 2 == 1:
c.append(i)
for j in c:
if j not in d:
d.append(j)
return d
or do not use for j in c and use directly:
return list(set(c))
for example:
array = [0, 1, 1, 7, 8, 3, 9, 3, 9, 9]
output: [0, 7, 8, 9]

Resources