Using map python with key argument - python-3.x

I have a function that looks like this:
def myFunct(arg1=None,arg2=None,arg3=None):
pass
I would like to use that function with a map function but with argument 1 and 3 only.
idea would be:
map(myFunct,list_arg1,list_arg3)
so each of the call would be myFunct(value1,arg3=value3)
How could I achieve that ?

You could use lambda to map the arguments to your keyword arguments.
def foo(arg1=None, arg2=None, arg3=None):
return arg1 + arg3
list1 = [3, 4, 5]
list2 = [5, 6, 7]
print(list(map(lambda x, y: foo(arg1=x, arg3=y), list1, list2)))

Another approach is to keep your function as is and modify what you are mapping over:
from itertools import repeat
def f(x = 0, y = 0, z = 0):
return sum((x,y,z))
map(f,range(1,10),repeat(0),range(21,30))
Although from a readability point of view, a simple generator expression might be preferable to any solution based on map, something along the lines of:
f(x = i,z = j) for i,j in zip(range(1,10),range(21,30)))

Related

Default array parameters python

I need to understand why the calls to this function amends to the array which got a default initialization in the function declaration? Appreciate if any reference to the API specs
def f(i, values = []):
values.append(i)
print(values)
return values
Calls to:
f(1) prints -> [1]
f(2) prints -> [1, 2]
f(3) prints -> [1, 2, 3]
and so one

How to multiply 2 input lists in python

Please help me understand how to code the following task in Python using input
Programming challenge description:
Write a short Python program that takes two arrays a and b of length n
storing int values, and returns the dot product of a and b. That is, it returns
an array c of length n such that c[i] = a[i] · b[i], for i = 0,...,n−1.
Test Input:
List1's input ==> 1 2 3
List2's input ==> 2 3 4
Expected Output: 2 6 12
Note that the dot product is defined in mathematics to be the sum of the elements of the vector c you want to build.
That said, here is a possibiliy using zip:
c = [x * y for x, y in zip(a, b)]
And the mathematical dot product would be:
sum(x * y for x, y in zip(a, b))
If the lists are read from the keyboard, they will be read as string, you have to convert them before applying the code above.
For instance:
a = [int(s) for s in input().split(",")]
b = [int(s) for s in input().split(",")]
c = [x * y for x, y in zip(a, b)]
Using for loops and appending
list_c = []
for a, b in zip(list_a, list_b):
list_c.append(a*b)
And now the same, but in the more compact list comprehension syntax
list_c = [a*b for a, b in zip(list_a, list_b)]
From iPython
>>> list_a = [1, 2, 3]
>>> list_b = [2, 3, 4]
>>> list_c = [a*b for a, b in zip(list_a, list_b)]
>>> list_c
[2, 6, 12]
The zip function packs the lists together, element-by-element:
>>> list(zip(list_a, list_b))
[(1, 2), (2, 3), (3, 4)]
And we use tuple unpacking to access the elements of each tuple.
From fetching the input and using map & lambda functions to provide the result. If you may want to print the result with spaces between (not as list), use the last line
list1, list2 = [], []
list1 = list(map(int, input().rstrip().split()))
list2 = list(map(int, input().rstrip().split()))
result_list = list(map(lambda x,y : x*y, list1, list2))
print(*result_list)
I came out with two solutions. Both or them are the ones that are expected in a Python introductory course:
#OPTION 1: We use the concatenation operator between lists.
def dot_product_noappend(list_a, list_b):
list_c = []
for i in range(len(list_a)):
list_c = list_c + [list_a[i]*list_b[i]]
return list_c
print(dot_product_noappend([1,2,3],[4,5,6])) #FUNCTION CALL TO SEE RESULT ON SCREEN
#OPTION 2: we use the append method
def dot_product_append(list_a, list_b):
list_c = []
for i in range(len(list_a)):
list_c.append(list_a[i]*list_b[i])
return list_c
print(dot_product_append([1,2,3],[4,5,6])) #FUNCTION CALL TO SEE RESULT ON SCREEN
Just note that the first method requires that you cast the product of integers to be a list before you can concatenate it to list_c. You do that by using braces ([[list_a[i]*list_b[i]] instead of list_a[i]*list_b[i]). Also note that braces are not necessary in the last method, because the append method does not require to pass a list as parameter.
I have added the two function calls with the values you provided, for you to see that it returns the correct result. Choose whatever function you like the most.

Python: How to find the average on each array in the list?

Lets say I have a list with three arrays as following:
[(1,2,0),(2,9,6),(2,3,6)]
Is it possible I get the average by diving each "slot" of the arrays in the list.
For example:
(1+2+2)/3, (2+0+9)/3, (0+6+6)/3
and make it become new arraylist with only 3 integers.
You can use zip to associate all of the elements in each of the interior tuples by index
tups = [(1,2,0),(2,9,6),(2,3,6)]
print([sum(x)/len(x) for x in zip(*tups)])
# [1.6666666666666667, 4.666666666666667, 4.0]
You can also do something like sum(x)//len(x) or round(sum(x)/len(x)) inside the list comprehension to get an integer.
Here are couple of ways you can do it.
data = [(1,2,0),(2,9,6),(2,3,6)]
avg_array = []
for tu in data:
avg_array.append(sum(tu)/len(tu))
print(avg_array)
using list comprehension
data = [(1,2,0),(2,9,6),(2,3,6)]
comp = [ sum(i)/len(i) for i in data]
print(comp)
Can be achieved by doing something like this.
Create an empty array. Loop through your current array and use the sum and len functions to calculate averages. Then append the average to your new array.
array = [(1,2,0),(2,9,6),(2,3,6)]
arraynew = []
for i in range(0,len(array)):
arraynew.append(sum(array[i]) / len(array[i]))
print arraynew
As you were told in the comments with sum and len it's pretty easy.
But in python I would do something like this, assuming you want to maintain decimal precision:
list = [(1, 2, 0), (2, 9, 6), (2, 3, 6)]
res = map(lambda l: round(float(sum(l)) / len(l), 2), list)
Output:
[1.0, 5.67, 3.67]
But as you said you wanted 3 ints in your question, would be like this:
res = map(lambda l: sum(l) / len(l), list)
Output:
[1, 5, 3]
Edit:
To sum the same index of each tuple, the most elegant method is the solution provided by #PatrickHaugh.
On the other hand, if you are not fond of list comprehensions and some built in functions as zip is, here's a little longer and less elegant version using a for loop:
arr = []
for i in range(0, len(list)):
arr.append(sum(l[i] for l in list) / len(list))
print(arr)
Output:
[1, 4, 4]

Pythonic and secure way to convert a list of integers to a string and vis-à-vis

I have a list of integers (e. g. [1, 2, 3] and want to convert them to one string (e. g. "1, 2, 3"). Later I will convert the string back into a list of integers.
Is my solution pythonic enough or is there a much easier way?
# init values
int_list = [1, 2, 3]
# list of integers to string
string = str(int_list)[1:-1]
# string to list of integers
int_list = [int(i) for i in string.split(',')]
By the way: My first approach was to do exec("int_list = [" + str + "]"). But using exec is absolutly not recommended.
Use map:
a = [1, 2, 3]
b = list(map(str, a))
c = list(map(int, b))
EDIT: if you want only one string, then
a = [1, 2, 3]
b = ",".join(map(str, a))
c = list(map(int, b.split(",")))
EDIT2: you can also use this to convert the map to a list. I don't like it too much, but it's an option:
c = [*map(int, b.split(","))]
# to string
a = [1,2,3]
s = repr(a)
print(s)
# from string
import ast
print(ast.literal_eval(s))
Unlike eval, literal_eval "can be used for safely evaluating strings containing Python values from untrusted sources without the need to parse the values oneself."

What is the preferred way to concatenate sequences in Python 3?

What is the preferred way to concatenate sequences in Python 3?
Right now, I'm doing:
import functools
import operator
def concatenate(sequences):
return functools.reduce(operator.add, sequences)
print(concatenate([['spam', 'eggs'], ['ham']]))
# ['spam', 'eggs', 'ham']
Needing to import two separate modules to do this seems clunky.
An alternative could be:
def concatenate(sequences):
concatenated_sequence = []
for sequence in sequences:
concatenated_sequence += sequence
return concatenated_sequence
However, this is incorrect because you don't know that the sequences are lists.
You could do:
import copy
def concatenate(sequences):
head, *tail = sequences
concatenated_sequence = copy.copy(head)
for sequence in sequences:
concatenated_sequence += sequence
return concatenated_sequence
But that seems horribly bug prone -- a direct call to copy? (I know head.copy() works for lists and tuples, but copy isn't part of the sequence ABC, so you can't rely on it... what if you get handed strings?). You have to copy to prevent mutation in case you get handed a MutableSequence. Moreover, this solution forces you to unpack the entire set of sequences first. Trying again:
import copy
def concatenate(sequences):
iterable = iter(sequences)
head = next(iterable)
concatenated_sequence = copy.copy(head)
for sequence in iterable:
concatenated_sequence += sequence
return concatenated_sequence
But come on... this is python! So... what is the preferred way to do this?
I'd use itertools.chain.from_iterable() instead:
import itertools
def chained(sequences):
return itertools.chain.from_iterable(sequences):
or, since you tagged this with python-3.3 you could use the new yield from syntax (look ma, no imports!):
def chained(sequences):
for seq in sequences:
yield from seq
which both return iterators (use list() on them if you must materialize the full list). Most of the time you do not need to construct a whole new sequence from concatenated sequences, really, you just want to loop over them to process and/or search for something instead.
Note that for strings, you should use str.join() instead of any of the techniques described either in my answer or your question:
concatenated = ''.join(sequence_of_strings)
Combined, to handle sequences fast and correct, I'd use:
def chained(sequences):
for seq in sequences:
yield from seq
def concatenate(sequences):
sequences = iter(sequences)
first = next(sequences)
if hasattr(first, 'join'):
return first + ''.join(sequences)
return first + type(first)(chained(sequences))
This works for tuples, lists and strings:
>>> concatenate(['abcd', 'efgh', 'ijkl'])
'abcdefghijkl'
>>> concatenate([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> concatenate([(1, 2, 3), (4, 5, 6), (7, 8, 9)])
(1, 2, 3, 4, 5, 6, 7, 8, 9)
and uses the faster ''.join() for a sequence of strings.
what is wrong with:
from itertools import chain
def chain_sequences(*sequences):
return chain(*sequences)
Use itertools.chain.from_iterable.
import itertools
def concatenate(sequences):
return list(itertools.chain.from_iterable(sequences))
The call to list is needed only if you need an actual new list, so skip it if you just iterate over this new sequence once.

Resources