Get indexes of longest repeated string - python

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))

Related

Is it possible to set a priority to elements in a list?

i'm trying to set a priority for each element in my list, here is the code :
mylist = []
state0 = [True, 2]
state1 = [False, 2]
state2 = [True, 3]
state3 = [True, 4]
state4 = [False, 3]
mylist.append(state0)
mylist.append(state1)
mylist.append(state2)
mylist.append(state3)
mylist.append(state4)
def function():
for element, priority in mylist:
if element is False and ...: # And priority is higher than the others
function()
The fact here, is that I need to retrieve an element in mylist that is False and its priority is higher than all the elements in mylist.
I don't know if there is a pythonic way to do that.
If you have any idea, i'll take it !
Thanks in advance.
You can use max with key base numbers, then find the max number and check if base max number.
from operator import itemgetter
max_num = max(mylist, key=itemgetter(1))[1]
# max(mylist, key=itemgetter(1)) -> [True, 4]
# [True, 4][1] -> 4
def function(mylist):
max_num = max(mylist, key=itemgetter(1))[1]
for element, priority in mylist:
if element is False and priority > max_num: # And priority is higher than the others
# Do waht you want
function(mylist)
You could make use of filter (remove True's) and sort by priority, so the first element of the sorted list has a high priority than the other ones:
mylist = [[True, 2], [False, 2], [True, 3], [True, 4], [False, 3]]
mylist = filter(lambda x: x[0] == False, mylist) # Keep all falses
print(
sorted(mylist, key=lambda x: (x[0], x[1]), reverse=1)[0]
) # sort by priority
Out:
[False, 3]
If you make your priority values negative, you can simply use min() to retrieve the element you want. Or if not, use a custom key argument to min() or max() to make the lowest-value-but-highest-priority element come out first, for example:
selected = min(mylist, key=lambda x:[x[0],-x[1]] )
print(selected is state4) # prints True
if selected[0] == False:
do_something_with( selected )
Your question implies you want to process just the one element whose priority is greatest. But if you want to process more, you can also do mylist.sort( key=... ) so that all the Falsies come out earlier than all the Truthies, in priority order.

How to change one element in a sublist using list comprhension

I am worrying in python, and I've a list composed by 8 sublists, made in this way: [[value1,value2,value3], ...].
I want to change to "False" only the third value (value3) in all sublists using a list comprhension, but my code does not work, and a I don't know why.
[[a, b, False] for a, b, _ in athlete_session_el['top_bottom_first']]
athlete_session_el['top_bottom_first'] is the list of sublists.
The following works:
athlete_session_el = {}
athlete_session_el['top_bottom_first'] = [[1,2,3],[1,2,3],[1,2,3]]
print([[sublist[0], sublist[1], False] for sublist in athlete_session_el['top_bottom_first'] ])
[[1, 2, False], [1, 2, False], [1, 2, False]]
You can try this
liste= [[1,2,3],[1,2,3],[1,2,3]]
comp = [False if indx ==2 else y for x in liste for indx, y in enumerate(x) ]

Using for loop to remove elements from a list is not working, but using list comprehension is fine

OK, this problem is actually solved, but I still want to know WHY. I am trying to remove elements from a 2-dimensional array, and here's the code:
print("adj in the while loop: ", adj)
for z in adj:
print("for loop: ", z)
if z[-1] is True:
adj.remove(z)
result += 1
print("adj after all execution: ", adj)
Console Output:
adj in the while loop: [[1, True], [0, 2, True], [1, True]]
for loop: [1, True]
for loop: [1, True]
adj after all execution: [[0, 2, True]]
This doesn't work as intended. The correct output after the execution should be [].
So I start to edit the code using list-comprehension.
Code for list-comprehension:
adj = [z for z in adj if z[-1] is not True]
It worked as intended. The output is [].
This confuses me. Why would these two seemingly identical methods yield different results? Can anyone explain that to me?
These two methods are not identical. In the list comprehension, you never call adj.remove(z).
The list comprehension is creating a new list as it iterates over adj, then you assign that (empty) list back to adj once it's done. It doesn't change adj while iterating, only after the last iteration.
You can definitely use .remove(), but iterate over a copy of the original and not the original itself:
adj = [[1, True], [0, 2, True], [1, True]]
for z in adj[:]:
print("for loop: ", z)
if z[-1] is True:
adj.remove(z)
result += 1
print("adj after all execution: ", adj)
which prints out an empty list.
Here, we iterate over the copy, but remove elements from the original. This avoids discrepancy that you see with your code.
Iteration over the list and at same time with it's inner block, if you use method remove or append for an element is not right way to do it. Basically better to change the coding to other way. As like Austin suggested in his code or use separate index instead of iterative index or element.
That is
adj = [[3, 4, 5, False], [8, 7, False], [0, True], [-1, False], [1, True], [0, 2, False], [0, 2, True], [1, True], [4, False]]
del_index = 0
for i in range(len(adj)):
print("for loop: ", adj[del_index])
if adj[del_index][-1] is True:
adj.remove(adj[del_index])
else:
del_index+=1
print("adj after all execution: ", adj)
Filter can applied for this purpose
filter(lambda elem: elem[-1] is True, adj)
This may crash your system since the append element to the list and same time iterating over the same.
crash_my_system = [0]
for i in crash_my_system: crash_my_system.append(i+1)
This is not only true for List. this is common to all mutable data structure such as Dict. Refer: Christoph Zwerschke's blog

Appending consecutive equal values to a list in 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.

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

Categories

Resources