#!/usr/bin/env python
new_trace=[1,2,2,3,2,1,4,3,2,1,3,4,3,5,6,4,7,6,5,4,5,4,6,6,5,6,4,4,5,6,7,7,6,5,5,7,6,5]
def extractIntervals(new_trace):
listofAppearances=[[new_trace[0]],[0],[-1]]
for i in range(0,len(new_trace)-1,1):
if new_trace[i] in listofAppearances[0]:
continue
else:
listofAppearances[0].append(new_trace[i])
listofAppearances[1].append(i)
listofAppearances[2].append(-1)
print(listofAppearances)
for j in range(len(new_trace)-1,0,-1):
for k in range(0,len(listofAppearances[0])-1,1):
if (new_trace[j]==listofAppearances[0][k]) and (listofAppearances[2][k]==-1):
listofAppearances[2][k]=j
else:
continue
print(listofAppearances)
def main():
extractLivenessIntervals(new_trace)
if __name__ == "__main__":
main()
In my code above I am trying to extract Intervals of appearance (delimited by 1st and last appearance indexes of every number in the list) The way I do it is I parse once the list and if the number still doesn't exist in listOfAppearances, then I append it to first column, the index to the second column and I set the 3rd column to -1.
I parse again the list in reverse every element is look for in the listofAppearances and the corresponding 3rd column is changed to the current index if still set to -1.
This works, but the first iteration when parsing the list backward has some issue that I can't figure out. the result I have with this example of a list is:
[[1, 2, 3, 4, 5, 6, 7], [0, 1, 3, 6, 13, 14, 16], [-1, -1, -1, -1, -1, -1, -1]]
[[1, 2, 3, 4, 5, 6, 7], [0, 1, 3, 6, 13, 14, 16], [9, 8, 12, 27, 37, 36, -1]]
As you can see the last element of the second list is still set to -1 which I don't understand why! I inspected every inch of the code and I can't see why is it this way!
Just change
for k in range(0, len(listofAppearances[0])-1, 1):
to
for k in range(0, len(listofAppearances[0]), 1):
in line 17.
Edit: you can get the same result by:
def extractIntervals(new_trace):
listofAppearances = [0, 0, 0]
listofAppearances[0] = list(set(new_trace))
# returns new_trace without repeated elements
listofAppearances[1] = [new_trace.index(i) for i in list(set(new_trace))]
# returns a list with the index of the first occurrence
# in new_trace of each element in list(set(new_trace))
listofAppearances[2] = [len(new_trace) - 1 - new_trace[::-1].index(i) for i in list(set(new_trace))]
# returns a list with the index of the last occurrence
# in new_trace of each element in list(set(new_trace))
print(listofAppearances)
Might I suggest processing a stream of values? First define a few helper functions, then use them to group each element with the positions at which it occurs.
from itertools import groupby
from operator import itemgetter
second = itemgetter(1)
first_and_last = itemgetter(0, -1)
def sort_and_group(seq, k):
return groupby(sorted(seq, key=k), k)
def extract_intervals(new_trace):
tmp1 = sort_and_group(enumerate(new_trace), second)
tmp2 = [(val, *first_and_last([x for x,_ in positions])) for val, positions in tmp1]
return zip(*tmp2)
new_trace=[1,2,2,3,2,1,4,3,2,1,3,4,3,5,6,4,7,6,5,4,5,4,6,6,5,6,4,4,5,6,7,7,6,5,5,7,6,5]
print(list(extract_intervals(new_trace)))
tmp1 is a pairing of each element with the list of positions at which it occurs.
tmp2 is a list of triples, consisting of a list element and the first and last position at which it occurs.
The call to zip "unzips" the list of triples into three tuples: the elements, the first positions, and the last positions.
Related
I was learning recursion and stumbled upon a question. How can I get the indexes of all the occurrences of an element in a list through recursion?
My understanding:
When the index equals to the length of the array it returns the array(or should return an array of indexes)
The first call increments the occurrence of fsf(found_so_far) and increments the index(when the if the condition is executed)
the second call increments just the index idx(the else part of the condition)
Flaws:
every time the function is called a new empty list(which stores results of all occurrences of the key) is created
the append function doesn't append the occurrences to the resultant list
after all the calls an empty list that is called by the else part of the condition returns an empty list(post calls/backtracking)
My code:
def allindex(arr, idx, fsf, key): #arr=array, idx=index, fsf=found so far, key=key to be found
list = []
if idx == len(arr):
return list
if arr[idx] == key:
allindex(arr, idx + 1, fsf + 1, 8)
list.append(idx)
return list
else:
allindex(arr, idx + 1, fsf, 8)
return list
arr = [2, 4, 5, 8, 1, 8, 6, 8, 7, 9]
allindex(arr, 0, 0, 8) #passes an (array,starting_index,found_so_far,key)
Expected output:
[3,5,7]
Got instead:
[]
The problem with your code is that you are creating a new list object each time you recursively call the function, since you are doing list = [] each time. (By the way, do not name a variable list, it is already a reserved keyword in Python that denotes the list type, here you can use indices_found for example)
What you want to do is actually pass down the same list to every call of the function :
def allindex(
arr, idx, fsf, key, found_indices
): # arr=array, idx=index, fsf=found so far, key=key to be found
if idx == len(arr):
return found_indices
if arr[idx] == key:
found_indices.append(idx)
allindex(arr, idx + 1, fsf + 1, 8, found_indices)
return found_indices
else:
allindex(arr, idx + 1, fsf, 8, found_indices)
return found_indices
This correctly returns [3, 5, 7].
def f(arr, val):
# solve the base case
if len(arr) == 0:
return []
# get solution for arr[1:]
res = f(arr[1:], val)
# add one to res for correct indexing
res = [i + 1 for i in res]
if arr[0] == val:
return [0] + res
return res
A basic flaw with the posted solution is:
list = []
Posted recursion always starts over with a new array which prevents solution from being accumulated.
Also, list is discouraged as a variable name in Python since it conflicts with builtin function.
Working recursive function
def allindex(arr, key, i = 0, indexes = None):
if indexes is None:
indexes = []
# Reached end of list (Base case)
if i == len(arr):
return indexes # no more recursion
# Found item
if arr[i] == key:
indexes.append(i)
# Recursive call to next index of array
allindex(arr, key, i+1, indexes)
return indexes
arr = [2, 4, 5, 8, 1, 8, 6, 8, 7, 9]
print(allindex(arr, 8))
Output: [3, 5, 7]
You can use enumerate to select the index of specific elements.
arr = [2, 4, 5, 8, 1, 8, 6, 8, 7, 9]
my_number = 8
index_list =[idx for idx, el in enumerate(arr) if el == my_number]
I've been given a homework task that asks me to find in a list of data the greatest continuous increase. i.e [1,2,3,4,5,3,1,2,3] the greatest static increase here is 4.
I've written a function that takes a single list and spits out a list of sublists like this.
def group_data(lst):
sublist= [[lst[0]]]
for i in range(1, len(lst)):
if lst[i-1] < lst[i]:
sublist[-1].append(lst[i])
else:
sublist.append([lst[i]])
return(sublist)
Which does what it's supposed to
group_data([1,2,3,4,5,6,7,8,9,10,1,2,3,5,4,7,8])
Out[3]: [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [1, 2, 3, 5], [4, 7, 8]]
And I now want to subtract the last element of each individual list from the first to find their differences. But I'm having difficulty figuring out how to map the function to each list rather than each element of the list. Any help would be greatly appreciated.
you can do it using map function where arr is your grouped list
list(map(lambda x: x[-1]-x[0], arr ))
For this problem I think itertools.groupby would be a good choice. Since your final goal is to find the difference of longest consecutive numbers:
from itertools import groupby
max_l = max([len(list(g)) - 1 for k, g in groupby(enumerate([1,2,3,4,5,6,7,8,9,10,1,2,3,5,4,7,8]), key=lambda x: x[0] - x[1])])
print(max_l)
#it will print 9
Explanation:
First groupby the numbers with the difference between index and number value. For example [0, 1, 2, 4] will create [0, 0, 0, 1] as the index of 0 is 0, so 0-0=0, for the second one 1-1=0. Then take the maximum length of the grouped list. Since you want difference, I used len(list(g)) - 1
I'm trying to do the following in python: given a list of lists and an integer i
input = [[1, 2, 3, 4], [1, 2, 3, 4], [5, 6, 7, 8]]
i = 1
I need to obtain another list which has all 1s for the elements of the i-th list, 0 otherwise
output = [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0]
I wrote this code
output = []
for sublist in range(0, len(input)):
for item in range(0, len(input[sublist])):
output.append(1 if sublist == i else 0)
and it obviously works, but since I'm a newbie in python I suppose there's a better 'pythonic' way of doing this.
I thought using map could work, but I can't get the index of the list with it.
Creating extra variable to get index of current element in interation is quite unpythonic. Usual alternative is usage of enumerate built-in function.
Return an enumerate object. sequence must be a sequence, an iterator,
or some other object which supports iteration. The next() method of
the iterator returned by enumerate() returns a tuple containing a
count (from start which defaults to 0) and the values obtained from
iterating over sequence.
You may use list comprehension with double loop inside it for concise one liner:
input_seq = [[1, 2, 3, 4], [1, 2, 3, 4], [5, 6, 7, 8]]
i = 1
o = [1 if idx == i else 0 for idx, l in enumerate(input_seq) for _ in l]
Alternatively,
o = [int(idx == i) for idx, l in enumerate(input_seq) for _ in l]
Underscore is just throwaway name, since in this case we don't care for actual values stored in input sublists.
Here's a 1-liner, but it's not really obvious:
output = [int(j == i) for j, sublist in enumerate(input) for _ in sublist]
Somewhat more obvious:
output = []
for j, sublist in enumerate(input):
output.extend([int(i == j)] * len(sublist))
Then "0 or 1?" is computed only once per sublist, which may or may not be more efficient.
I need to perform a triple cut. My function takes as parameter list of int, and somewhere in that list there is 27 and 28. What I need to do is to check what comes first 27 or 28, everything before the 27 or 28(depending upon what comes first) goes to the bottom of the list and everything after 27 or 28 (depending upon what comes second will go the top of the list.
Here is an example:
>>> test_list = [1, 28, 3, 4, 27, 5, 6, 7, 8]
>>> triple_cut(test_list)
>>> test_list = [5, 6, 7, 8, 28, 3, 4, 27, 1]
Here is what I have so far
#find the index positions of the two jokers
find_joker1 = deck.index(27)
find_joker2 = deck.index(28)
print(find_joker1, find_joker2)
new_list = []
# use selection to check which joker occurs first
if(find_joker1 > find_joker2): # joker2(28) occurs first in the list
# loop throgh each element in the list that occurs before Joker1
# and move them to the end of the list
# move element that occur after Joker1(27) to the top of the list
for i in deck:
if(deck.index(i) > find_joker1): # elements that occur after second joker
new_list.append(i) # move those element to the top of the list
new_list.append(28) # add Joker2
for i in deck: # element between the two Jokers
if(deck.index(i) > find_joker2 and deck.index(i) < find_joker1):
new_list.append(i)
new_list.append(27)
for i in deck: # elements before the first joker
if(deck.index(i) < find_joker2):
new_list.append(i)
print(new_list)
Can be solved by slicing.
def triple_cut(lst):
a=lst.index(27)
b=lst.index(28)
if a>b:
return lst[a+1:]+ lst[b:a+1]+ lst[:b]
else:
return lst[b+1:]+ lst[a:b+1]+ lst[:a]
What actually happenning:
Slice everything after the bigger indexed one.
Slice from the lower indexed one to upper indexed one.
Slice everything before the lower indexed one.
Add all together.
N.B: During slicing, first index is inclusive and second index is exclusive.
Demo,
>>test_list = [1, 28, 3, 4, 27, 5, 6, 7, 8]
>>tripplecut(test_list)
[5, 6, 7, 8, 27, 3, 4, 28, 1]
Some explanation:
By slicing, you can get a part of a list. First see, how actually slicing works:
lst[start:end:increment]
For relevance to your question, skip the increment part. Default increment is 1, just what we need. So, we will slice a list like below:
lst[start:end]
Let's do some experiments with your given list.
>>> test_list = [1, 28, 3, 4, 27, 5, 6, 7, 8]
Say, we want a list from index 2(3) to index 5(27). Simply do:
>>> test_list[2:6]
[3,4,27]
Why I've used 6 in place of 5. That's because:
In case of slicing, the start index is inclusive, but the end index is exclusive.
What if we want a list from start to index 4(27). Do:
>> test_list[:5]
[1,28,3,4,27]
If we want index 3 to end? Simply do:
>>test_list[3:]
[4, 27, 5, 6, 7, 8]
Hope that will help you a bit.
Since you don't actually need to know which is which, you can just find the two indexes and slice.
def triple_cut(lst):
first, second = [i for i, e in enumerate(lst) if e in [27, 28]]
return lst[second+1:] + lst[first:second+1]+ lst[:first]
I've an array my_array and I want, due to specific reasons ignore the values -5 and -10 of it (yes, in the example below there's not a -10 but in other arrays I've to manage yes), and get the index of the three minimum values of the array, and append them to a new list titled lista_indices_candidatos.
This is my code.
my_array = [4, -5, 10, 4, 4, 4, 0, 4, 4]
a = np.array(my_array)
indices = a.argsort()
indices = indices[a[indices] != -5]
indices = indices[a[indices] != -10]
lista_indices_candidatos = []
for i in indices[:3]:
lista_indices_candidatos.append(i)
print lista_indices_candidatos
This gets me the index of the 3 minimum values [6, 0, 3] from the array [4, -5, 10, 4, 4, 4, 0, 4, 4]
The thing is that, if there are repeated values, this get's me the first three minimum values (the first 4 (index 0) the second 4 (index 3), ignoring the rest 4's of the array.
How can I change the code to get completely randomly the three minimum values, without taking always the first three?
myArray = [4, -5, 10, 4, 4, 4, 0, 4, 4]
myUniqueArray = list(set(myArray))
myUniqueArray.sort()
return [myArray.index(myUniqueArray[0]), myArray.index(myUniqueArray[1]), myArray.index(myUniqueArray[2])]
.index would not give you a random index in the sense that it will always be the same value for a give set of input list but you could play with that part.
I haven't introduced randomness, because it don't really see the point for doing this.
If you need the first 3 lowest positive values:
sorted([x for x in my_array if x >= 0])[:3]
If you need the first three lowest positive values and their initial index:
sorted([(x,idx) for idx,x in enumerate(my_array) if x >= 0], key=lambda t: t[0])[:3]
If you just need the first 3 lowest positive values initial indexes:
[i for x,i in sorted([(x,idx) for idx,x in enumerate(my_array) if x >= 0], key=lambda t: t[0])[:3]]
My take is that you want to get 3 random indices for values in my_array, excluding [-10, -5], the 3 random indices must be chosen within the index list of the 3 lowest values of the remaining set, right?
What about this:
from random import sample
my_array = [4, -5, 10, 4, 4, 4, 0, 4, 4]
sample([i for i, x in enumerate(my_array) if x in sorted(set(my_array) - {-10, -5})[:3]], 3)
Factoring out the limited set of values, that would be:
from random import sample
my_array = [4, -5, 10, 4, 4, 4, 0, 4, 4]
filtered_list = sorted(set(my_array) - {-10, -5})[:3]
# Print 3 sample indices from my_array
print sample([i for i, x in enumerate(my_array) if x in filtered_list], 3)
Ok, I'm also not sure what you are trying to achieve. I like the simplicity of Nasha's answer, but I think you want to always have the index of the 0 in the result set. The way I understand you, you want the index of the lowest three values and only if one of those values is listed more than once, do you want to pick randomly from those.
Here's my try a solution:
import random
my_array = [4, -5, 10, 4, 4, 4, 0, 4, 4]
my_dict = {}
lista_indices_candidatos = []
for index, item in enumerate(my_array):
try:
my_dict[item] = my_dict[item] + [index]
except:
my_dict[item] = [index]
for i in [x for x in sorted(my_array) if x != -10 and x != -5][:3]:
lista_indices_candidatos.append(random.choice(my_dict[i]))
print lista_indices_candidatos
In this solution, I build a dictionary with all the values from my_array as keys. The values of the dictionary is a list of indexes these numbers have in my_array. I then use a list comprehension and slicing to get the three lowest values to iterate over in the for loop. There, I can randomly pick an index for a given value by randomly selecting from my_dict.
I bet there are better ways to achieve what you want to achieve, though. Maybe you can let us know what it is you are trying to do so we can improve on our answers.
After reading your comment, I see that you do not actually want a completely random selection, but instead a random selection without repetition. So here's an updated version.
import random
my_array = [4, -5, 10, 4, 4, 4, 0, 4, 4]
my_dict = {}
lista_indices_candidatos = []
for index, item in enumerate(my_array):
try:
my_dict[item] = my_dict[item] + [index]
except:
my_dict[item] = [index]
for l in my_dict:
random.shuffle(my_dict[l])
for i in [x for x in sorted(my_array) if x != -10 and x != -5][:3]:
lista_indices_candidatos.append(my_dict[i].pop())
print lista_indices_candidatos
How about this one:
import random
def eachIndexSorted(a): # ... without -5 and -10
for value in sorted(set(a) - { -5, -10 }):
indexes = [ i for i in range(len(a)) if a[i] == value ]
random.shuffle(indexes)
for i in indexes:
yield i
def firstN(iterator, n):
for i in range(n):
yield iterator.next()
print list(firstN(eachIndexSorted(my_array), 3))
If you have very large data, then sorting the complete set might be too costly; finding each next minimum iteratively might then be a better approach. (Ask for more details if this aspect is unclear and important for you.)