Appending consecutive equal values to a list in python - python

So, I'm working on a python script that will take a list of integers (S), and output a list of lists based off of the integers in S, and the sum of each list must be the same value.
I'm having a problem with appending values that are the same. Python seems to be aggregating them as the same value, when I want it to create another entry.
I've tried using .extend with the same results. Also, I've read up and seen posts about multipling by a constant to create multiple values. The problem here is that I don't know how many times I will be adding the element. Is there an easy solution to this? Sorry if this has been answered before, but I can't find it.
import itertools
def arrangeBoxes(stacks, arr):
perms = itertools.permutations(arr)
total = sum(arr)
stackSize = total / stacks
if (not(stackSize.is_integer())):
return [False, []]
for i in perms:
tempSum = 0
tempArr = []
stackArr = []
built = False
for j in i:
tempArr.append(j)
if (sum(tempArr) == stackSize):
stackArr.append(tempArr)
tempArr = []
if (j == i[len(i) - 1]):
built = True
break
else:
if (j == i[len(i) - 1]):
break
if (built):
return [True, stackArr]
return [False, []]
# Doesn't Work.
# Output: [True, [[3]]]
# Should be: [True, [[3], [3], [3]]
print(str(arrangeBoxes(3, [3, 3, 3])))
# Works fine.
# Output: [True, [[2, 1], [2, 1], [3]]]
print(str(arrangeBoxes(3, [2, 1, 2, 1, 3])))

you're explicitly breaking and returning when
j == i[len(i) - 1])
In the first iteration (of (3,3,3)) j, is obviously 3, and any cell in i is obviously 3 - this will be immediately True and break, then return.
Iterate over indices, if you want to check if you're in the last index, not over the element:
for perm in perms:
...
for j in range(len(perm)):
...
if j == len(perm) - 1:
return [True, stackArr]
No need for else or break.

Related

recursive sums for a non_uniform list

def _findsum (arr, N):
if len(arr)== 1:
return arr[0]
else:
return arr[0]+_findSum(arr[1:], N)
arr =[]
arr = [1, 2, 3, 4, 5]
N = len(arr)
ans =_findSum(arr,N)
print (ans)
_findsum(arr,N)
OutPut= 15
I need to write a recursive program to sum all elements of a non-uniform nested list.
I need the code to print something similar to the list below.
[7, [4, 6], 2, [1, 3, 5]].
Your question is a little unclear but I'm guessing you need to print the sum of all the numbers present in the parent list. Here's a hint.
In the function, iterate through the list which is passed as a parameter. If the type of the current element is list, call the function with that list as the parameter. If not, return the sum of the elements.
def findsum(arr):
if len(arr) == 0:
return 0
first = arr[0]
rest = arr[1:]
if type(first) == list:
return findsum(first) + findsum(rest)
else:
return first + findsum(rest)
x = [1, [[2, 3], 4]]
print(findsum(x)) # returns 10
If I understood your question correctly, this program should return the sum of the elements in your nested list.
A shorter version looks like this:
def findsum(arr):
return sum((findsum(element) if (type(element) == list) else element) for element in arr)
x = [7, [[2,[-1]]]]
print(findsum(x)) # returns 8

Get indexes of longest repeated string

I have this list:
l = [True, True, False, True, True, True, False, False]
How do I get the indexes of the longest repeated substring True ?
The output would be: [3,4,5]
This is what I have tried:
get_index=[]
counter = 0
for i,li in enumerate(l):
if li == True:
counter = counter +1
get_index.append([i,counter])
else:
counter = 0
I get a list like that: [[0, 1], [1, 2], [3, 1], [4, 2], [5, 3]]
Now the idea is to retain only the pairs where the left numbers are increasing without interruption (i.e. 3,4,5) and where the last right number has the highest score of all pairs. … but I don't know how to do that?
Try this:
clusters = [[]]
for index, b in enumerate(l):
if b:
# Append to the existing cluster if this item is True
clusters[-1].append(index)
elif clusters[-1]:
# If this item is False, finalize the previous cluster and init
# a new empty one (but don't bother if the previous cluster was
# already empty)
clusters.append([])
# Print the longest cluster
print(max(clusters, key=len))

Find unique pairs in list of pairs

I have a (large) list of lists of integers, e.g.,
a = [
[1, 2],
[3, 6],
[2, 1],
[3, 5],
[3, 6]
]
Most of the pairs will appear twice, where the order of the integers doesn't matter (i.e., [1, 2] is equivalent to [2, 1]). I'd now like to find the pairs that appear only once, and get a Boolean list indicating that. For the above example,
b = [False, False, False, True, False]
Since a is typically large, I'd like to avoid explicit loops. Mapping to frozensets may be advised, but I'm not sure if that's overkill.
ctr = Counter(frozenset(x) for x in a)
b = [ctr[frozenset(x)] == 1 for x in a]
We can use Counter to get counts of each list (turn list to frozenset to ignore order) and then for each list check if it only appears once.
Here's a solution with NumPy that 10 times faster than the suggested frozenset solution:
a = numpy.array(a)
a.sort(axis=1)
b = numpy.ascontiguousarray(a).view(
numpy.dtype((numpy.void, a.dtype.itemsize * a.shape[1]))
)
_, inv, ct = numpy.unique(b, return_inverse=True, return_counts=True)
print(ct[inv] == 1)
Sorting is fast and makes sure that the edges [i, j], [j, i] in the original array identify with each other. Much faster than frozensets or tuples.
Row uniquification inspired by https://stackoverflow.com/a/16973510/353337.
Speed comparison for different array sizes:
The plot was created with
from collections import Counter
import numpy
import perfplot
def fs(a):
ctr = Counter(frozenset(x) for x in a)
b = [ctr[frozenset(x)] == 1 for x in a]
return b
def with_numpy(a):
a = numpy.array(a)
a.sort(axis=1)
b = numpy.ascontiguousarray(a).view(
numpy.dtype((numpy.void, a.dtype.itemsize * a.shape[1]))
)
_, inv, ct = numpy.unique(b, return_inverse=True, return_counts=True)
res = ct[inv] == 1
return res
perfplot.save(
"out.png",
setup=lambda n: numpy.random.randint(0, 10, size=(n, 2)),
kernels=[fs, with_numpy],
labels=["frozenset", "numpy"],
n_range=[2 ** k for k in range(15)],
xlabel="len(a)",
)
You could scan the list from start to end, while maintaining a map of encountered pairs to their first position. Whenever you process a pair, you check to see if you've encountered it before. If that's the case, both the first encounter's index in b and the current encounter's index must be set to False. Otherwise, we just add the current index to the map of encountered pairs and change nothing about b. b will start initially all True. To keep things equivalent wrt [1,2] and [2,1], I'd first simply sort the pair, to obtain a stable representation. The code would look something like this:
def proc(a):
b = [True] * len(a) # Better way to allocate this
filter = {}
idx = 0
for p in a:
m = min(p)
M = max(p)
pp = (m, M)
if pp in filter:
# We've found the element once previously
# Need to mark both it and the current value as "False"
# If we encounter pp multiple times, we'll set the initial
# value to False multiple times, but that's not an issue
b[filter[pp]] = False
b[idx] = False
else:
# This is the first time we encounter pp, so we just add it
# to the filter for possible later encounters, but don't affect
# b at all.
filter[pp] = idx
idx++
return b
The time complexity is O(len(a)) which is good, but the space complexity is also O(len(a)) (for filter), so this might not be so great. Depending on how flexible you are, you can use an approximate filter such as a Bloom filter.
#-*- coding : utf-8 -*-
a = [[1, 2], [3, 6], [2, 1], [3, 5], [3, 6]]
result = filter(lambda el:(a.count([el[0],el[1]]) + a.count([el[1],el[0]]) == 1),a)
bool_res = [ (a.count([el[0],el[1]]) + a.count([el[1],el[0]]) == 1) for el in a]
print result
print bool_res
wich gives :
[[3, 5]]
[False, False, False, True, False]
Use a dictionary for an O(n) solution.
a = [ [1, 2], [3, 6], [2, 1], [3, 5], [3, 6] ]
dict = {}
boolList = []
# Iterate through a
for i in range (len(a)):
# Assume that this element is not a duplicate
# This 'True' is added to the corresponding index i of boolList
boolList += [True]
# Set elem to the current pair in the list
elem = a[i]
# If elem is in ascending order, it will be entered into the map as is
if elem[0] <= elem[1]:
key = repr(elem)
# If not, change it into ascending order so keys can easily be compared
else:
key = repr( [ elem[1] ] + [ elem[0] ])
# If this pair has not yet been seen, add it as a key to the dictionary
# with the value a list containing its index in a.
if key not in dict:
dict[key] = [i]
# If this pair is a duploicate, add the new index to the dict. The value
# of the key will contain a list containing the indeces of that pair in a.
else:
# Change the value to contain the new index
dict[key] += [i]
# Change boolList for this to True for this index
boolList[i] = False
# If this is the first duplicate for the pair, make the first
# occurrence of the pair into a duplicate as well.
if len(dict[key]) <= 2:
boolList[ dict[key][0] ] = False
print a
print boolList

Multi-dimensional array is entirely (aside the first value) set to appended value

I'm making a function to find all the combinations for a given set of options. When I append a combination as a list to the main list of total combinations (the combinations are indexes, to be taken from the list of options later), all of the existing lists are changed to the list I just appended, apart from the first.
def allCombos(opts):
limit = len(opts) - 1
combos = []
for n in range(1, 3):
combo = [0] * n
print(combo) # going to remove this
goal = [limit] * n
pointer = 0
overflowed = False
while True:
if combo[pointer] == limit:
pointer += 1
overflowed = True
else:
if overflowed:
combo[pointer] += 1
for i in range(pointer):
combo[i] = 0
pointer = 0
combos.append(combo)
print(combo) # I will change this
else:
combo[pointer] += 1
combos.append(combo)
print(combo) # and this
if combo == goal:
break
allCombos(["foo", "bar"])
outputs
[0]
[1]
[0, 0]
[1, 0]
[0, 1]
[1, 1]
whereas
def allCombos(opts):
limit = len(opts) - 1
combos = []
for n in range(1, 3):
combo = [0] * n
goal = [limit] * n
pointer = 0
overflowed = False
while True:
if combo[pointer] == limit:
pointer += 1
overflowed = True
else:
if overflowed:
combo[pointer] += 1
for i in range(pointer):
combo[i] = 0
pointer = 0
combos.append(combo)
print(combos) # changed
else:
combo[pointer] += 1
combos.append(combo)
print(combos) # changed
if combo == goal:
break
print("\n" + str(combos)) #added
allCombos(["foo", "bar"])
outputs
[[1]]
[[1], [1, 0]]
[[1], [0, 1], [0, 1]]
[[1], [1, 1], [1, 1], [1, 1]]
[[1], [1, 1], [1, 1], [1, 1]]
This seems odd, as the only specified modifications of combos seems to be the appending.
I've looked for other questions with similar issues, but I couldn't find any.
Thanks in advance!
You're appending several references to combo to combos. When you change combo, those references all point to the modified list. Compare to this simple example:
>>> x=[1,2]
>>> y=[]
>>> y.append(x)
>>> y.append(x)
>>> y
[[1, 2], [1, 2]]
>>> x[0]+=1
>>> y
[[2, 2], [2, 2]]
>>>
Notice that combo originally starts out as [0], but you never see that in the output. That's because it's been changed to [1]. When you get to the top of the loop, you set combo to [0,0]. Why doesn't that affect combos? Because you've set combo to a new value. The reference in combos points to a different object than the newly-created combo. Now you start changing combo in place, and appending it to the list. You just get multiple copies of the same thing.
If this isn't clear, try setting the limit to 3 instead of 2. Can you predict what the output will be?
I think that Gary van der Merwe made a good suggestion, but I believe he's thinking of itertools.product, not itertools.combinations.

Comparing values in two lists in Python

In Python 2.7, I have two lists of integers:
x = [1, 3, 2, 0, 2]
y = [1, 2, 2, 3, 1]
I want to create a third list which indicates whether each element in x and y is identical, to yield:
z = [1, 0, 1, 0, 0]
How can I do this using list comprehension?
My attempt is:
z = [i == j for i,j in ...]
But I don't know how to complete it.
You are looking for zip
z = [i == j for i,j in zip(x,y)]
But you better add int call to get your desired output
>>> z = [int(i == j) for i,j in zip(x,y)]
>>> z
[1, 0, 1, 0, 0]
else you'll get a list like [True, False, True, False, False]
As ajcr mentions in a comment, it is better to use itertools.izip instead of zip if the lists are very long. This is because it returns an iterator instead of a list. This is mentioned in the documentation
Like zip() except that it returns an iterator instead of a list.
demo
>>> from itertools import izip
>>> z = [int(i == j) for i,j in izip(x,y)]
>>> z
[1, 0, 1, 0, 0]
You can change it a little bit and do:
[x[i] == y[i] for i in xrange(len(x))]
If you use Python3 - change xrange to range
While a list comprehension was specified in the question and the answers above are probably better, I thought I'd chime in with a recursive solution:
def compare_lists(a, b, res=[]):
if len(a) == len(b):
if a == []:
return res
else:
if a[0] == b[0]:
res.append(1)
else:
res.append(0)
return compare_lists(a[1:], b[1:])
else:
return "Lists are of different length."

Categories

Resources