Why does unpacking give results in tuple - python

I am learning arbitrary value parameter and reading stackoverflow this and this answers and other tutorials I already understood what *args and **kwargs do in python but I am facing some errors. I have two doubts, first one is:
If I run this code print(w) then I am getting this output:
def hi(*w):
print(w)
kl = 1, 2, 3, 4
hi(kl)
output:
((1, 2, 3, 4),)
but if I run this code with print(*w) then I am getting this output:
code:
def hi(*w):
print(*w)
kl = 1, 2, 3, 4
hi(kl)
output:
(1, 2, 3, 4)
My second doubt is:
je = {"a": 2, "b": 4, "c": 6, 4: 5}
for j in je:
print(*je)
output
b a 4 c
b a 4 c
b a 4 c
b a 4 c
What exactly is *je doing there? How is it working in iteration?

When you use * in declaration of the arguments def hi(*w):, it means that all the arguments will be compressed to the tuple, e.g.:
hi(kl, kl) # ((1, 2, 3, 4), (1, 2, 3, 4))
After when you use print(*w) * run unpack of your tuple.
je={"a":2,"b":4,"c":6,4:5}
for j in je:
print(*je)
In every iteration you use unpack of your dict (you use je and get the keys of your dict like [j for j in je])
https://docs.python.org/2/tutorial/controlflow.html#tut-unpacking-arguments

Your first case, it's because you're passing kl into the function as a tuple, not as arbitrary values. Hence, *w will expand into a single element tuple with kl as the first value.
You're essentially calling:
hi((1, 2, 3, 4))
However, what I suspect you want is
hi(1, 2, 3, 4)
# or in your case
hi(*kl)
When printing in python 3, print is a function, so again. When w is a tuple and you call it like:
print(w)
# you'll get the tuple printed:
# (1, 2, 3, 4)
However, again, you can call it with arguments like:
print(1, 2, 3, 4)
# or in your case
print(*w)
# 1 2 3 4
For your second part, look at it converted to a list first:
list({"a":2,"b":4,"c":6,4:5})
# ["b", "a", 4, "c"]
# Note, dictionaries are unordered and so the list could be in any order.
If you were to then pass that to print using the * expansion:
print("b", "a", 4, c)
# or in your case
print(*["b", "a", 4, "c"])
Just note, that the * does the default iteration for you. If you wanted some other values, use je.values() or je.items()

Related

Why am I getting a KeyError after reading values from .txt file?

So I'm trying to change an already-working program to read from a .txt file, but I only see a KeyError.
#V = ([1,2,3,4,5])
#E = ([(1,2),(1,3),(2,3),(3,5),(5,4)])
import ast
with open('v.txt') as V:
A = ast.literal_eval(V.read())
with open('e.txt') as E:
B = ast.literal_eval(E.read())
print(A)
print(B)
indegree = {}
outdegree = {}
for x in A:
indegree[x] = 0
outdegree[x] = 0
for x,y in B:
outdegree[x] += 1
indegree[y] += 1
for x in A:
print("Outdegree for vertex", x,"=", outdegree[x])
print("Indegree for vertex", x,"=", indegree[x])
The output is:
[(1, 2, 3, 4, 5)]
[(1, 2), (1, 3), (2, 3), (3, 5), (5, 4)]
line 21, in
outdegree[x] += 1
KeyError: 1
When I run it with values from #V and #E and the beginning of the code, it runs completely fine.
It seems like the commented 'V' above has the shape
([1,2,3,4,5])
This gets read in and interpreted to the inner list, when I run it on my console, becoming:
[1,2,3,4,5]
However, notice in your print statements that instead, A is written as a list of a single tuple. The nesting is different.
[(1, 2, 3, 4, 5)]
When you iterate over the first dimension of A, you'll only instantiate the hashmap as follows:
{(1, 2, 3, 4, 5): 0}
My guess is the intended behavior is {1: 0, 2:0, ...}. I'd suggest that you use standard data formats (like tsv/csv) to simplify loading the data. Second, if you switch the order of brackets, you should get your intended answer

How to store calculated values?

I have been trying to write code which gives the solution of the number of ways of reaching a sum, which is specified. This is very similar to the subset sums problem which I have found online (Finding all possible combinations of numbers to reach a given sum).
I modified slightly the code so that it reuses numbers multiple times.
object_list = [(2, 50), (3, 100), (5, 140)] # the first number in the tuple is my weight and the second is my cost
max_weight = 17
weight_values = [int(i[0]) for i in object_list]
cost_values = [int(i[1]) for i in object_list]
def subset_sum(objects, max_weight, weights=[]):
w = sum(weights)
if w == max_weight:
print("sum(%s)=%s" % (weights, max_weight))
if w >= max_weight:
return
for i in range(len(objects)):
o = objects[i]
subset_sum(objects, max_weight, weights + [o])
if __name__ == "__main__":
subset_sum(weight_values, max_weight)
print(subset_sum(weight_values, max_weight))
This gives the solution:
sum([2, 2, 2, 2, 2, 2, 2, 3])=17
sum([2, 2, 2, 2, 2, 2, 3, 2])=17
sum([2, 2, 2, 2, 2, 2, 5])=17
sum([2, 2, 2, 2, 2, 3, 2, 2])=17
...
So on so forth.
Unlike the original I am using a list of tuples and then taking the first value of the tuple to make a list. This is the same with the last value.
The part I am currently stuck on is how to store these values and reuse them in the next part of the code.I had a look at this post but I couldn't understand it (Python: How to store the result of an executed function and re-use later?).
So I want to store the part of the solution which stores [2, 2, 2, 2, 2, 2, 2, 3] from the solution sum([2, 2, 2, 2, 2, 2, 2, 3])=17. I want to do this for all solutions because in the next step i am going to replace the numbers with the next part of the tuple (so 2 will be replaced by 50 because the tuple that 2 is in is (2,50)). Then I am going to use this to print another sum value with the replaced numbers and print the highest value (probably going to sort the solutions from highest to lowest and print the first value in the list)
I tried using a dictionary to try and replace the values after the calculation but i couldn't manage to do it.
I tried:
dictionary = dict(zip(weight_values, cost_values))
Any help is appreciated. before anyone asks Ia have looked online for solutions and have no one else to ask help from, since the only person i know who has a background in coding is my brother who isn't at home

Python generating all nondecreasing sequences

I am having trouble finding a way to do this in a Pythonic way. I assume I can use itertools somehow because I've done something similar before but can't remember what I did.
I am trying to generate all non-decreasing lists of length L where each element can take on a value between 1 and N. For example if L=3 and N=3 then [1,1,1],[1,1,2],[1,1,3],[1,2,2],[1,2,3], etc.
You can do this using itertools.combinations_with_replacement:
>>> L, N = 3,3
>>> cc = combinations_with_replacement(range(1, N+1), L)
>>> for c in cc: print(c)
(1, 1, 1)
(1, 1, 2)
(1, 1, 3)
(1, 2, 2)
(1, 2, 3)
(1, 3, 3)
(2, 2, 2)
(2, 2, 3)
(2, 3, 3)
(3, 3, 3)
This works because c_w_r preserves the order of the input, and since we're passing a nondecreasing sequence in, we only get nondecreasing tuples out.
(It's easy to convert to lists if you really need those as opposed to tuples.)

Python-search function

I want to write a search function that takes in a value x and a sorted sequence and returns the position that the value should go to by iterating through the elements of the sequence starting from the first element. The position that x should go to in the list should be the first position such that it will be less than or equal to the next element in the list.
Example:>>> search(-5, (1, 5, 10))——0
>>> search(3, (1, 5, 10))——1
Building a list of every item would be a bit of a waste of resources if there were big gaps in the list, instead you can just iterate through each list item until the input is bigger than the value.
In terms of your code -
def search(input,inputList):
for i in range( len( inputList ) ):
if inputList[i]>input:
return i
return len( inputList )
print search(-5, (1, 5, 10))
#Result: 0
print search(3, (1, 5, 10))
#Result: 1
To insert it into the list, this would work, I split the list in 2 based on the index and add the value in the middle.
def insert(input,inputList):
index = search(input,inputList) #Get where the value should be inserted
newInput = [input]+list(inputList[index:]) #Add the end of the list to the input
if index:
newInput = list(inputList[:index])+newInput #Add the start of the list if the index isn't 0
return newInput
print insert(-5, (1, 5, 10))
#Result: (-5, 1, 5, 10)
print insert(3, (1, 5, 10))
#Result: (1, 3, 5, 10)
since someone has answered a similar question, I will just draw a rough skeleton of what u may want to do.
declare a list and populate it with your stuff;
mylist = [1, 2, 3, 5, 5, 6, 7]
then just make a function and iterate the list;
def my_func( x, mylist):
for i in mylist:
if((mylist[i] == x)|| (mylist[i] > x)):
return i
Given 3 in list (1, 2, 3, 4, 5), the function should return index 2.
Given 3 in list (1, 2, 4, 5, 6), it should still return 2
You may want to check my python code, because I have not checked this for errors, I am assuming you know some python and if you have the skeleton, you should crack it. And Oh, python cares about the tabbibg I did.

Creating dynamic sublists from a list /sequence in python

Im trying to write a function that creates set of dynamic sublists each containing 5 elements from a list passed to it.Here's my attempt at the code
def sublists(seq):
i=0
x=[]
while i<len(seq)-1:
j=0
while j<5:
X.append(seq[i]) # How do I change X after it reaches size 5?
#return set of sublists
EDIT:
Sample input: [1,2,3,4,5,6,7,8,9,10]
Expected output: [[1,2,3,4,5],[6,7,8,9,10]]
Well, for starters, you'll need to (or at least should) have two lists, a temporary one and a permanent one that you return (Also you will need to increase j and i or, more practically, use a for loop, but I assume you just forgot to post that).
EDIT removed first code as the style given doesn't match easily with the expected results, see other two possibilities.
Or, more sensibly:
def sublists(seq):
x=[]
for i in range(0,len(seq),5):
x.append(seq[i:i+5])
return x
Or, more sensibly again, a simple list comprehension:
def sublists(seq):
return [seq[i:i+5] for i in range(0,len(seq),5)]
When given the list:
l = [1,2,3,4,5,6,7,8,9,10]
They will return
[[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
Have you considered using itertools.combinations(...)?
For example:
>>> from itertools import combinations
>>> l = [1,2,3,4,5,6]
>>> list(combinations(l, 5))
[(1, 2, 3, 4, 5), (1, 2, 3, 4, 6), (1, 2, 3, 5, 6), (1, 2, 4, 5, 6), (1, 3, 4, 5, 6), (2, 3, 4, 5, 6)]
By "dynamic sublists", do you mean break up the list into groups of five elements? This is similar to your approach:
def sublists(lst, n):
ret = []
i = 0
while i < len(lst):
ret.append(seq[i:i+n])
i += n
return ret
Or, using iterators:
def sublists(seq, n):
it = iter(seq)
while True:
r = list(itertools.islice(it, 5))
if not r:
break
yield r
which will return an iterator of lists over list of length up to five. (If you took out the list call, weird things would happen if you didn't access the iterators in the same order.)

Categories