How to pass a map to a function in Python 3? - python-3.x

I get a map of numbers from user and I want to pass the map to a function. I am able to display the map, but I can't find its length. I understand that in Python 3, maps have no length and they have to be converted in lists, but I had no success with that. I also noticed that if I attempt to display the length of the map before calling function info, then the info() will print an empty map.
def info(phys):
print("phys =",list(phys)) # it displays correctly only if I comment line 10
print("len =",len(list(phys))) # it always displays 0 and I expect 3
for i in phys:
print(str(i))
return
phys = map(int, input().strip().split()) # I pass "1 2 3"
print("len(phys) =",len(list(phys))) # if this command executes before next, line 2 will print "phys = []"
info(phys)

The result of a map() call is a generator which will yield resulting values only once. See relevant documentation about map.
>>> phys = map(int, input().strip().split())
1 2 3 4
>>> list(phys)
[1, 2, 3, 4]
>>> list(phys)
[] # Second attempt to iterate through "phys" does not return anything anymore
Apparently you want to materialize the values and work with them later. Then store them:
>>> phys = map(int, input().strip().split())
1 2 3 4
>>> result = list(phys)
>>> len(result)
4
>>> result[1]
2
>>> result[-2:]
[3, 4]

Related

How to take two inputs in one line separated by space in python

So I am practicing in hacker earth and I have to take two inputs in a single line separated by space.
The below code is what I used:
x, y = [x for x in input("Enter two value: ").split()]
It is supposed to take input that looks like '2 5'
And it is returning an error:
Execution failed
ValueError : not enough values to unpack (expected 2, got 1)
Stack Trace:
Traceback (most recent call last):
File "/tmp/165461120/user_code.py", line 13, in
x, y = [x for x in input("Enter two value: ").split()]
ValueError: not enough values to unpack (expected 2, got 1)
What I think I understood is that it is giving two values as a single string. If so how do I take separate them and convert them into integers?
To take two inputs
x, y = input("Enter two value: ").split()
This should do the trick. To convert to int you can do it seprately on the both x and y.
Or better way is to use a map function
x, y = map(int, input().split())
For your case, only typecasting is remaining, so that splitted numbers becomes int. So, just you have to add
x, y = [int(x) for x in input("Enter two value: ").split()]
Alternatively, For taking 2 inputs in single line, you can use map also
x, y = map(int, input().split())
This is happening because Hacker Earth, in almost all cases, gives its input line by line.
In almost all cases, the inputs are of the form below.
1
2 3 4
5
6 7 8
This will differ on problem by problem basis and needs to be personalized for each problem.
You are getting the error not enough values to unpack because Hacker Earth is giving only a single input, and you are expecting 2. If it had been more than 2, then the error would have been too many values to unpack.
In all probability its because you are trying to input the number of test cases, which is the first input, and a single number input, in most hacker earth problems.
Process-01 : using list comprehension
whole_line = input() # 1 2 3 4 5
strings = whole_line.split(' ') # ['1', '2', '3', '4', '5']
# remove extra space within numbers if any from list
numbers = [int(num) for num in strings if len(num)>0] # [1, 2, 3, 4, 5]
print(numbers) # [1, 2, 3, 4, 5]
Now you can write down the whole logic within one line like below
numbers = [ int(num) for num in input().split(' ') if len(num)>0 ]
print(numbers)
Process-02 : using filter and map function
whole_line = input() # 1 2 3 4 5
strings = whole_line.split(' ') # ['1', '2', '3', '4', '5']
# remove extra space within numbers if any from list
strings = list(filter(lambda x :len(x)>0 ,strings))
numbers = list(map(int,strings)) # convert each string to int
print(numbers) # [1, 2, 3, 4, 5]
Now you can write down the whole logic within one line like below
numbers = list(map(int,filter(lambda x : len(x)>0,input().split(' '))))
print(numbers)
In [20]: a,b = raw_input().split()
12 12.2
In [21]: a = int(a)
Out[21]: 12
In [22]: b = float(b)
Out[22]: 12.2
You can't do this in a one-liner (or at least not without some super duper extra hackz0r skills -- or semicolons), but python is not made for one-liners.

How to use heapq module

I don't understand how I can properly use heapq module.
I realized that without transforming my list to a heap (without using heapify) I can still use other functions which require a heap as input (heappop, heappush..). So when do I need to use heapify?
Should I create an empty list, transform it to a heap using heapify, and then use it? I tried this. I got TypeError.
my_list = heapq.heapify([0])
heapq.heappush(my_list, -8)
TypeError: heap argument must be a list
heapq.heappush(my_list, -8)
In the example below I can push -8 to my list with heappush if I don't transform my list to a heap. However when I want to see the min element of the heap, it gives me 0. In the heapq documentation it says that I can reach the min element using the index 0.
my_list = [0]
heapq.heappush(my_list, -8)
print(my_list, my_list[0])
output: [0, -8] 0
I'm trying to use it in a loop, so I want to be able to perform quick push and pop operations without transforming a list to a heap in each iteration, it would take O(N)
You should use heapify when you don't start from an empty list and you want to transform the list to a heap inplace.
>>> queue = [1,9,2,4]
>>> heapify(queue)
>>> queue
[1, 4, 2, 9]
When you start from an empty list, then you can perform the operations such as heappush, heappop, and heappushpop directly on the list.
Example:
>>> queue = []
>>> heappush(queue, 3)
>>> heappush(queue, 1)
>>> heappush(queue, 4)
>>> heappop(queue)
1
>>> heappop(queue)
3
>>> heappop(queue)
4
You get an error, because you are using the return value of heapify, which is None since it's inplace.
>>> res = heapify([1,9,2,4])
>>> res is None
True

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.

How to reassign multiple variables (if possible) with an iterator in Python 3

update Adding a usage example to better explain why I'm trying to elicit this behavior. See update at end of post. Added better syntax for links and added a link to article suggested as an answer.
I am trying to use an iterator to alter the value of a list of variables.
>>> a = 1
>>> b = 2
>>> c = 3
>>> for i in [a,b,c]:
i += 1
>>> a,b,c #Expecting (2, 3, 4)
(1, 2, 3)
This doesn't appear to work, I've tried some other ways (see below) without success.
1. Will someone please tell me a better way to approach this problem?
2. Will someone explain why the example above doesn't work as I expected?
3. Will someone tell me how/where I could have found #2 in python help documentation?
Places I've previously looked for answers...
StackOverflow question "reassign variable to original value defined prior to the loop at start of each"
StackOverflow question on reassigning variables (but not a list of variables)
Python docs: Objects and Value Types
Python docs section 3.1.3
I feel like the last reference to the python docs might have the answer, but I was overwhelmed with the amount of info, my brain is tired, and I'm hoping someone on s.o. can help.
also tried...
>>> help(__name__)
Help on module __main__:
NAME
__main__
DATA
__annotations__ = {}
a = 1
b = 2
c = 3
i = 4
FILE
(built-in)
but if anything, this only confused me further.
Lastly I tried...
>>> a = 1
>>> b = 2
>>> c = 3
>>> R = [a, b, c]
>>> for i in range(3):
R[i] += 1
>>> a, b, c #Hoping for (2, 3, 4)
(1, 2, 3)
>>> R #Kind of expected (1, 2, 3) based on the above behavior
[2, 3, 4]
update
I used the list for convenience, since I could iterate through its members. The part I'm not understanding is that when I say...
>>> x = [a, b, c]
I am creating a list such that
x = [the value assigned to a,
the value assigned to b,
the value assigned to c]
rather than
x = [the variable a, the variable b, the variable c]
so when I am trying to use the syntax
>>> x[0] += 1 #take the current ITEM in place 0 and increment its value by 1.
instead of
>>> a += 1
it is instead interpreted as...
take the current VALUE of the ITEM in place 0,
increment that VALUE by 1,
this is the new VALUE of ITEM in place 0 ...
and I lose the reference to the original ITEM... the variable a.
Here is a usage example of why I am trying to elicit this behavior...
>>> class breakfast():
>>> def __init__(self, eggs=None, bacon=None, spam=None):
>>> self.eggs = eggs
>>> self.bacon = bacon
>>> self.spam = spam
>>> updateOrder = False
>>> updateItems = []
>>> for i in [self.eggs, self.bacon, self.spam]:
>>> if i == None:
>>> updateOrder = True
>>> updateItems.append(i)
>>> else:
>>> pass
>>> if updateOrder:
>>> self.updateOrder(itemsToUpdate = updateItems)
>>>
>>> def updateOrder(self, itemsToUpdate):
>>> for i in itemsToUpdate: ###also tried...
>>> ###for i in range(len(itemsToUpdate)):
>>> print('You can\'t order None, so I am updating your order to 0 for some of your items.')
>>> i = 0
>>> ###itemsToUpdate[i] = 0
>>>
>>> #Finally, the good part, behavior I'm after...
>>> myBreakfast = breakfast(eggs=2,bacon=3)
You can't order None, so I am updating your order to 0 for some of your items.
>>> myBreakfast.spam == 0 #hoping for True....
False
The only way I know would work to get this behavior is to instead say...
>>> ...
>>> def updateOrder(self):
>>> orderUpdated=False
>>> if self.eggs == None:
>>> self.eggs = 0
>>> orderUpdated = True
>>> if self.bacon == None:
>>> self.bacon = 0
>>> orderUpdated = True
>>> if self.spam == None:
>>> self.spam = 0
>>> orderUpdated = True
>>> if orderUpdated:
>>> print('You can\'t order None, so I am updating your order')
However, if there are (lots) more than just 3 items on the menu the code for updateOrder would become very long and worse repetitive.
You have to use a loop and change the each value of the list during the loop
a=[1, 2, 3]
for i in range(len(a)):
a[i] += 1
Output will be
[2, 3, 4]
To access and change values in a list, you need to select items based on their location (you can also use slices). So, a[0] = 1, a[1] = 2 and so on. To change the value of a[0], you need to assign a new value to it (as done in the for loop).
Your example does not work because you are just changing the value of i (which is 1, then 2, then 3), instead of actually changing the list. You are not selecting any item from the list itself.
The documentation is given here (see section 3.1.3)
EDIT
Based on your clarification: Creating a list of variables that have been defined elsewhere:
a, b, c = 5, 6, 7
letters = [a, b, c]
# See id of variable a
id(a)
# 94619952681856
# See id of letters[0]
id(letters[0]
# 94619952681856
# Add 1 to letters[0]
letters[0] += 1
# See id of letters[0]
# 94619952681888
As you can see, when the list is first created, the item in the list points to the same variable However, as soon as the value in the list is changed, python creates a new item, so that the original value is unchanged.
This works the other way around also. Any change in the variable a will not affect the list, as once the variable is modified, its id will change, while the id of the item in the list will not.
And in the breakfast example, why don't you just assign 0 as the default value of each dish, instead of None? It would be a lot easier, unless there is some other reason for it.
EDIT 2:
If you need to update your attributes in the way that you have given, you would need to use the setattr method
class breakfast():
def __init__(self, eggs=None, bacon=None, spam=None):
self.eggs = eggs
self.bacon = bacon
self.spam = spam
# Create a list of attributes. This will return [self, eggs,bacon,spam]
attributes = list(locals().keys())
attributes.remove('self') # Remove self from the list
updateItems = []
for i in attributes:
# Check if the attribute is None or not
if getattr(self, i) == None:
updateItems.append(i)
else:
pass
for i in updateItems:
setattr(self, i, 0) # Set the attributes that are None to 0

How to turn a string lists into a lists?

There are other threads about turning strings inside a lists into different data types. I want to turn a string that is in the form of a lists into a lists. Like this: "[5,1,4,1]" = [5,1,4,1]
I need this because I am writing a program that requires the user to input a lists
Example of problem:
>>> x = input()
[3,4,1,5]
>>> x
'[3,4,1,5]'
>>> type(x)
<class 'str'>
If you mean evaluate python objects like this:
x = eval('[3,4,1,5]');
print (x);
print(type(x) is list)
[3, 4, 1, 5]
True
Use this with caution as it can execute anything user will input. Better use a parser to get native lists. Use JSON for input and parse it.
Use eval() for your purpose. eval() is used for converting code within a string to real code:
>>> mystring = '[3, 5, 1, 2, 3]'
>>> mylist = eval(mystring)
>>> mylist
[3, 5, 1, 2, 3]
>>> mystring = '{4: "hello", 2:"bye"}'
>>> eval(mystring)[4]
'hello'
>>>
Use exec() to actually run functions:
>>> while True:
... inp = raw_input('Enter your input: ')
... exec(inp)
...
Enter your input: print 'hello'
hello
Enter your input: x = 1
Enter your input: print x
1
Enter your input: import math
Enter your input: print math.sqrt(4)
2.0
In your scenario:
>>> x = input()
[3,4,1,5]
>>> x = eval(x)
>>> x
[3, 4, 1, 5]
>>> type(x)
<type 'list'>
>>>
Thanks for your input guys, but I would prefer not to eval() because it is unsafe.
Someone actually posted the answer that allowed me to solve this but then they deleted it. I am going to reposts that answer:
values = input("Enter values as lists here")
l1 = json.loads(values)
You can use ast.literal_eval for this purpose.
Safely evaluate an expression node or a string containing a Python
expression. The string or node provided may only consist of the
following Python literal structures: strings, bytes, numbers, tuples,
lists, dicts, sets, booleans, and None.
This can be used for safely evaluating strings containing Python
expressions from untrusted sources without the need to parse the
values oneself.
>>> import ast
>>> val = ast.literal_eval('[1,2,3]')
>>> val
[1, 2, 3]
Just remember to check that it's actually a list:
>>> isinstance(val, list)
True

Resources