python while loop does not show correct output? - python

This is quite strange, I am quite sure that the code works without the while loop:
target = [[1],]
add = [2,4]
count = 0
while count < 2:
temp = []
for i in target:
temp += [i, i]
target = temp[:]
print('before', target)
idx = 0
while idx < len(target):
target[idx].append(add[idx])
idx += 1
print('after', target)
add += add
count += 1
Here I have target as a nested list that contains number, I have add just as a list of numbers. My idea is to double the target every loop, and add one item from add to one sub-list of target and double the add afterwards.
I am getting the result:
before [[1], [1]]
after [[1, 2, 4], [1, 2, 4]]
before [[1, 2, 4], [1, 2, 4], [1, 2, 4], [1, 2, 4]]
after [[1, 2, 4, 2, 4, 2, 4], [1, 2, 4, 2, 4, 2, 4], [1, 2, 4, 2, 4, 2, 4], [1, 2, 4, 2, 4, 2, 4]]
if you look at the before and after, the whole add was added to each sub-list of target, instead of adding add[0] to target[0], then add[1] to target[1] showed below as my expectation:
before [[1], [1]]
after [[1, 2], [1, 4]]
before [[1, 2], [1, 4], [1, 2], [1, 4]]
after [[1, 2, 2], [1, 4, 4], [1, 2, 2], [1, 4, 4]]
without the outer while loop:
target = [[1],[1]]
add = [2,4]
count = 0
idx = 0
while idx < len(target):
target[idx].append(add[idx])
idx += 1
print(target)
# >>>
[[1, 2], [1, 4]]
Can't really understand why

The problem is in this block of code:
temp = []
for i in target:
temp += [i, i]
target = temp[:]
When it loops over target, it pulls out each item, in this case a list ([1]). This specific list (not copies) is then added twice to the temp list. What you need to do is copy when building temp:
temp = []
for i in target:
temp += [i[:], i[:]]
target = temp

Related

Trying to write a combinations function in Python on my own, not working

I'm trying to solve this problem here: https://codingbat.com/prob/p252079?parent=/home/peter#norvig.com
In math, a "combination" of a set of things is a subset of the things. We define the function combinations(things, k) to be a list of all the subsets of exactly k elements of things. Conceptually, that's all there is, but there are some questions to settle: (A) how do we represent a subset? (B) What order are the elements within each subset? (C) What order to we list the subsets? Here's what we will agree to: (A) a subset will be a list. (B) The order of elements within a list will be the same as the order within 'things'. So, for example, for combinations([1, 2, 3], 2) one of the subsets will be [1, 2]; whereas [2, 1] is not a subset. (C) The order of subsets will be lexicographical or sorted order -- that is, combinations([1, 2, 3], 2) returns [ [1, 2], [1, 3], 2, 3] ] because [1, 2] < [1, 3] < [2, 3]. You might want to use the function 'sorted' to make sure the results you return are properly ordered.
combinations([1, 2, 3, 4, 5], 2) → [[1, 2], [1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5], [3, 4], [3, 5], [4, 5]]
combinations([1, 2, 3], 2) → [[1, 2], [1, 3], [2, 3]]
combinations([1, 2, 3, 4, 5, 6], 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]]
Here's my code:
def combinations(things, k):
if k == 0 or k == len(things):
return [things]
elif len(things) < k:
return
else:
finalcomb = []
subcomb1 = combinations(things[1:], k - 1)
subcomb2 = combinations(things[1:], k)
for i in range(len(combinations(things[1:], k - 1))):
firstelement = [things[0]]
firstelement += combinations(things[1:], k - 1)[i]
finalcomb.append(firstelement)
for j in range(len(combinations(things[1:], k))):
finalcomb.append(combinations(things[1:], k)[j])
return finalcomb
However, this is the output:
Haven't hit 10 reputation yet so it's a link to the error. I'm not sure what I did wrong, can anybody help me out? Thank you so much.
The problem is this. When k == 0 it shouldn't return [things]. It should return an empty array. Similar to when len(things) < k:. This is because, when k == 0, it means we that we have already found all the numbers for that specific combination.
But there's one more problem. We're returning an empty array. However, in the for loops, we're iterating over the returned array. So if the array is empty, nothing happens. So what we should really return is an empty 2D array. I won't go into too much detail about what the problem is since it's better for you to try and understand why it's not working. Try adding print statements inside and outside the for loops.
Anyway, the working code looks like this:
def combinations(things, k):
if k == len(things):
return [things[:]]
if len(things) < k or k == 0:
return [[]]
finalcomb = []
subcomb1 = combinations(things[1:], k - 1)
subcomb2 = combinations(things[1:], k)
for comb in subcomb1:
firstelement = [things[0]]
firstelement += comb
finalcomb.append(firstelement)
finalcomb += subcomb2
return finalcomb
Note a few things:
Use the variables you've already assigned (I'm assuming you forgot about them)
Lists can be concatenated using +, similar to strings. If you return within an if statement, you don't need an else for the next line since if the if statement is satisfied, it would definitely not go to the else.
You simply can try using itertools:
import itertools
output = []
for nums in itertools.combinations([1, 2, 3, 4, 5], 2):
output.append(list(nums))
print(output)
output:
[[1, 2], [1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5], [3, 4], [3, 5], [4, 5]]
For 3 nums:
import itertools
output = []
for nums in itertools.combinations([1, 2, 3, 4, 5], 3):
output.append(list(nums))
print(output)
Output:
[[1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 3, 4], [1, 3, 5], [1, 4, 5], [2, 3, 4], [2, 3, 5], [2, 4, 5], [3, 4, 5]]

implementation error in Python recursive expression

I'm solving the problem.
You have to leave the last list, but the previous list is printed out again.
def merge(xs,ys):
# xs, ys, ss = xs, ys, []
xs, ys, ss = xs[:], ys[:], []
while xs!=[] and ys!=[]:
if xs[0] <= ys[0]:
ss.append(xs[0])
xs.remove(xs[0])
else:
ss.append(ys[0])
ys.remove(ys[0])
ss.extend(xs)
ss.extend(ys)
return ss
accumulator = []
remain = []
def merge2R(xss):
if len(xss)% 2 != 0 :
OExcept = len(xss)-1
remain.append((xss[OExcept]))
xss.remove(xss[OExcept])
if xss != []:
accumulator.append(merge(xss[0],xss[1]))
xss.remove(xss[0])
xss.remove(xss[0])
return merge2R(xss)
else:
return accumulator + remain
The result comes out like this.
How can I fix it?
>>> merge2R([[2],[1,3],[4,6,7],[5,8],[9]])
[[1, 2, 3], [4, 5, 6, 7, 8], [1, 2, 3], [4, 5, 6, 7, 8], [9]]
Desired result value:
>>> merge2R([[2],[1,3],[4,6,7],[5,8]])
[[1,2,3], [4,5,6,7,8]]
>>> merge2R([[2],[1,3],[4,6,7],[5,8],[9]])
[[1,2,3], [4,5,6,7,8], [9]]
Your code was working, you just needed to reset accumulator and remain
def merge2R(xss):
# Declare use of globals
global remain
global accumulator
if len(xss) % 2 != 0:
OExcept = len(xss)-1
remain.append((xss[OExcept]))
xss.remove(xss[OExcept])
if xss != []:
accumulator.append(merge(xss[0], xss[1]))
xss.remove(xss[0])
xss.remove(xss[0])
return merge2R(xss)
else:
x = accumulator + remain
# Must reset accumulator and remain
accumulator = []
remain = []
return x
Because you initialise both arrays as empty, then append to them:
# Remain
remain.append((xss[OExcept]))
# Accumulator
accumulator.append(merge(xss[0], xss[1]))
After you have finished with the data in those arrays (at end of function) you need to discard it:
accumulator = []
remain = []
The result of not discarding these arrays is evident when calling the function with the same argument multiple times:
print(merge2R([[2], [1, 3]]))
print(merge2R([[2], [1, 3]]))
print(merge2R([[2], [1, 3]]))
print(merge2R([[2], [1, 3]]))
print(merge2R([[2], [1, 3]]))
[[1, 2, 3]]
[[1, 2, 3], [1, 2, 3]]
[[1, 2, 3], [1, 2, 3], [1, 2, 3]]
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]
[[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]

Creation of lists depending on key values of a Python dictionary

everyone!
I have this dictionary which contains name of files as keys and some data as values.
In the name of the file there is some float number, which indicates if the test that was done on this data was on positive or negative of some field.
I want to separate this dictionary into two lists, eg: positive and negative. These two list corresponds to the float values of the name of the files containing positive and negative
The following code separated the values according to the float number. But return 3D list.
Question How can I use list comprehension to have a 2D list as a result in this case?
mainDictlist = [{'A1_0.5.txt':[[4,4,4],[4,4,4]],'B1_-0.5.txt':[[1,2,3],[1,2,3]],'A2_0.5.txt'[[2,2,2],[2,2,2]],'B2_-0.5.txt':[[1,1,1],[1,1,1]]}]
def findfloat(keys):
lst_numberStr = re.findall(r'[*+-]?\d+\.\d+', keys)
v = float(lst_numberStr[0])
return v
positive = []
negative = []
for item in mainDictlist:
for k, v in item.items():
findFloat = findfloat(k)
if findFloat > 0:
positive.append(item[k])
if findFloat < 0:
negative.append(item[k])
print('List Pos',positive)
print('List Neg',negative)
Returns
>>>List Pos [[[4, 4, 4], [4, 4, 4]], [[2, 2, 2], [2, 2, 2]]]
>>>List Neg [[[1, 2, 3], [1, 2, 3]], [[1, 1, 1], [1, 1, 1]]]
Desired Return
List Pos [[4, 4, 4], [4, 4, 4]], [[2, 2, 2], [2, 2, 2]]
List Neg [[1, 2, 3], [1, 2, 3]], [[1, 1, 1], [1, 1, 1]]
Use list.extend
Ex:
positive = []
negative = []
for item in mainDictlist:
for k, v in item.items():
findFloat = findfloat(k)
if findFloat > 0:
positive.extend(item[k])
if findFloat < 0:
negative.extend(item[k])
print('List Pos',positive)
print('List Neg',negative)
Output:
List Pos [[4, 4, 4], [4, 4, 4], [2, 2, 2], [2, 2, 2]]
List Neg [[1, 2, 3], [1, 2, 3], [1, 1, 1], [1, 1, 1]]
Your example of desired return is not a 2D list, but two separate lists.
In order to get a 2D list like [[4, 4, 4], [4, 4, 4], [2, 2, 2], [2, 2, 2]] you can replace positive.append(item[k]) with positive += v and do the same for negative.
Also, judging from the example you provided, filenames with positive floats doesn't contain - while those with negative do. So, separation of values can be done this way:
positive = []
negative = []
for item in mainDictlist:
for k, v in item.items():
if "-" in k:
negative += v
else:
positive += v
Hope this helps.

How to pack consecutive duplicates of list elements into sublists?

How can I "pack" consecutive duplicated elements in a list into sublists of the repeated element?
What I mean is:
l = [1, 1, 1, 2, 2, 3, 4, 4, 1]
pack(l) -> [[1,1,1], [2,2], [3], [4, 4], [1]]
I want to do this problem in a very basic way as I have just started i.e using loops and list methods. I have looked for other methods but they were difficult for me to understand
For removing the duplicates instead of packing them, see Removing elements that have consecutive duplicates
You can use groupby:
from itertools import groupby
def pack(List):
result = []
for key, group in groupby(List):
result.append(list(group))
return result
l = [1, 1, 1, 2, 2, 3, 4, 4, 1]
print(pack(l))
Or one-line:
l = [1, 1, 1, 2, 2, 3, 4, 4, 1]
result = [list(group) for key,group in groupby(l)]
# [[1, 1, 1], [2, 2], [3], [4, 4], [1]]
You can use:
lst = [1, 1, 1, 2, 2, 3, 4, 4, 1]
# bootstrap: initialize a sublist with the first element of lst
out = [[lst[0]]]
for it1, it2 in zip(lst, lst[1:]):
# if previous item and current one are equal, append result to the last sublist
if it1 == it2:
out[-1].append(it2)
# else append a new empty sublist
else:
out.append([it2])
Output:
>>> out
[[1, 1, 1], [2, 2], [3], [4, 4], [1]]
This code will do:
data = [0,0,1,2,3,4,4,5,6,6,6,7,8,9,4,4,9,9,9,9,9,3,3,2,45,2,11,11,11]
newdata=[]
for i,l in enumerate(data):
if i==0 or l!=data[i-1]:
newdata.append([l])
else:
newdata[-1].append(l)
#Output
[[0,0],[1],[2],[3],[4,4],[5],[6,6,6],[7],[8],[9],[4,4],[9,9,9,9,9],[3,3],[2],[45],[2],[11,11,11]]

Python program to shift elements of array

I am trying to create a python program to shuffle an array so that the horizontal and vertical rows never have a repeat number.
Input: [1,2,3,4]
Output:
1 2 3 4
2 3 4 1
3 4 1 2
4 1 2 3
My program calculates the shifting of each element correctly, but when it appends the list to the output list, the output list only has repeat copies of the last item in the list.
def numbers(list_of_numbers):
finalValues = [list_of_numbers]
#print(list_of_numbers)
for i in range(1,len(list_of_numbers)):
print("Last array of final: ", finalValues[-1])
tempArray = finalValues[-1]
print("Temp Array: ",tempArray)
temp = tempArray[0]
for j in range(0,len(list_of_numbers)-1):
tempArray[j] = tempArray[j+1]
tempArray[-1] = temp
finalValues.append(tempArray)
print("Final Values: ",finalValues)
return finalValues
numbers([1,2,3,4])
Program Output
[[4, 1, 2, 3], [4, 1, 2, 3], [4, 1, 2, 3], [4, 1, 2, 3]]
Correct Output
[[1,2,3,4], [2,3,4,1], [3,4,1,2], [4,1,2,3]]
The problem comes from the line:
tempArray = finalValues[-1]
You don't create a copy of the previous list, but only a new name to refer to it. After that, all changes you make to tempArray are actually changes to this list, and when you finally do:
finalValues.append(tempArray)
you just add another reference to this same list in finalValues.
In the end, finalValues contains 4 references to the same list, which you can access with finalValues[0], finalValues[1]...
What you need is to create a new list by copying the previous one. One way to do it is to use a slice:
tempArray = finalValues[-1][:]
You can find other ways to close or copy a list in this question
And so, the complete code gives the expected output:
Last array of final: [1, 2, 3, 4]
Temp Array: [1, 2, 3, 4]
Final Values: [[1, 2, 3, 4], [2, 3, 4, 1]]
Last array of final: [2, 3, 4, 1]
Temp Array: [2, 3, 4, 1]
Final Values: [[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2]]
Last array of final: [3, 4, 1, 2]
Temp Array: [3, 4, 1, 2]
Final Values: [[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
Thierry has provided a very comprehensive explanation of why your code doesn't work as you expect. As such it is the best answer to your question.I have added my answer just as an example of you you can code this in a less complex way .
create the 2d list with the first index as list of numbers. for each iteration take the last index of temp and slice from index 1 to the end then add on index 0.
then return the list
def numbers(list_of_numbers):
temp = [list_of_numbers]
for _ in range(1, len(list_of_numbers)):
temp.append(temp[-1][1:] + temp[-1][0:1])
return temp
print(numbers([1,2,3,4]))
OUTPUT
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
The problems is in shallow assignment of arrays. You should make deep copy, to really clone arrays, to make them independent.
I did it in your own code. There are a few changes of your code:
import copy that it have been added to first row.
Three usages of copy.deepcopy function instead of =(simple assignment).
import copy
def numbers(list_of_numbers):
finalValues = copy.deepcopy([list_of_numbers])
#print(list_of_numbers)
for i in range(1,len(list_of_numbers)):
print("Last array of final: ", finalValues[-1])
tempArray = copy.deepcopy(finalValues[-1])
print("Temp Array: ",tempArray)
temp = tempArray[0]
for j in range(0,len(list_of_numbers)-1):
tempArray[j] = tempArray[j+1]
tempArray[-1] = temp
finalValues.append(copy.deepcopy(tempArray))
print("Final Values: ",finalValues)
return finalValues
numbers([1,2,3,4])
Program Output
[[4, 1, 2, 3], [4, 1, 2, 3], [4, 1, 2, 3], [4, 1, 2, 3]]
Program Output
[[1,2,3,4], [2,3,4,1], [3,4,1,2], [4,1,2,3]]

Categories