Python: how to find a range of indexes from small to large? - python

I have 2 arrays. First is an array of rows. Second is an array of indents (think indenting text in a Word document)
1.
['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
2.
['1', '2', '3', '1', '2', '2', '2', '2', '1', '2']
I am struggling with finding a range of variables from a small number to the next bigger one.
My desired output would be
'1', '2', '3'
'1', '2', '3'
also,
'4', '5', '6', '7', '8'
'1', '2', '2', '2', '2'
I want to save the indexes of the of the array that stops when the next number is smaller than the previous.
Such as arraySaved = [['1', '3'],['4', '8']['9', '10']]
I keep getting 'out of index errors' and the saved indexes are not reflecting the correct range
Code I've tried:
num = 0
arrayOfIndexes = []
for x in range(0, len(array1)):
small= array2[int(num)]
num = int(num)+1
big = array2[int(num)]
if(big - num <=0):
arrayOfIndexes.append(num)

I believe this accomplishes what you want, if I interpreted your question correctly:
indents = ['1', '2', '3', '1', '2', '2', '2', '2', '1', '2']
arraySaved = []; temp = [0] #Initialize temporary list
for idx, i in enumerate(indents):
if idx==len(indents)-1:
temp.append(idx)
arraySaved.append(temp) #Reached end of list
elif indents[idx+1]<i: #Ending index of temporary list
temp.append(idx)
arraySaved.append(temp) #Store temporary list
temp = []; temp.append(idx+1) #Reset temporary list and begin new one
print(arraySaved)
Yields:
[[0, 2], [3, 7], [8, 9]]
Keep in mind that your desired output is the upper and lower bounds of the row indices after being separated into individually increasing indent counts. Therefore, you do not actually need the list rows, since you can just enumerate the list indents. The answer above is equivalent to your desired output if you keep in mind that Python indexes from 0, not 1.
Figured I would add that if you really want the row numbers indexed from 1, then you can do the following:
arraySaved = [[i+1 for i in j] for j in arraySaved]
Gives:
[[2, 3], [4, 8], [9, 10]]
Explanation
temp is simply a list used to temporarily store the indices of the values in indents that correspond to the starting and ending indices for each individual outputted list eventually stored in arraySaved. We need to initialize temp as well with the first index of the list, i.e. 0.
for idx, i in enumerate(indents): simply loops through the values inside of the list indents, where enumerate also unpacks the indices of the values inside of the list as well
The first if statement accounts for the case that the current index in the loop is the last one in the list, because then idx+1 would exceed the dimensions of the list being iterated on. If either of the criteria in the if statements are satisfied, then the current index is stored in the temp variable. If the ending index criteria is satisfied then the temp list is reset after being appended to arraySaved.
Hope that helps!

Related

How to remove and consecutively merge elements in a list [duplicate]

This question already has answers here:
How do I split a list into equally-sized chunks?
(66 answers)
Closed 1 year ago.
Let's say we have a list:
listA = ['stack', 'overflow', '1', '2', '3', '4', '1', '5', '3', '7', '2', '3', 'L', '1', ..., 'a', '23', 'Q', '1']
I want to create a new list such as:
new_list = ['1234', '1537', '23L1', ..., 'a23Q1']
So, in this case I want to create a new list using "listA" by removing first two elements and merging all next elements in groups of 4, so the elements: 1, 2, 3, 4; are one element now.
How to approach this in case that I have a very long list to modify. Also, would be nice to know how to approach this problem in case I don't need to create a new list, if all I want is just to modify the list I already have (such as: listA = ['1234', '1537', '23L1', ..., 'a23Q1']). Thanks.
You can create an iterator over that list and then use zip with four identical copies of that iterator to combine each four consecutive elements:
>>> it = iter(listA[2:])
>>> [''.join(x) for x in zip(*[it]*4)]
['1234', '1537', '23L1', 'a23Q1']
itertools.islice allows you to avoid making a temporary copy of that list via slicing:
>>> import itertools
>>> it = itertools.islice(iter(listA), 2, None)
For your specific question, I would just loop through it.
I would do something like this. (Sorry if the format is a bit off this is one of my first answers) This will loop through and combine all complete sets of 4 elements. You could add custom logic if you wanted to keep the end as well. If you don't want to create a new list you can just use "ListA" and ignore the data scrubbing I did by using ListB.
listA = ['stack', 'overflow', '1', '2', '3', '4', '1', '5', '3', '7', '2', '3', 'L', '1', 'a', '23', 'Q', '1']
listB = listA[2:] # remove first two elements
partialList = []
wholeList = []
position = 0
for element in listB:
if position < 4:
partialList.append(element)
position+=1
else:
wholeList.append(''.join(partialList))
position = 0
partialList = []
partialList.append(element)
print(wholeList)
If you don't need a new list you could just create one then set the old list to equal it afterwards. You could try this iterative approach:
listA = ['stack', 'overflow', '1', '2', '3', '4', '1', '5', '3', '7', '2', '3', 'L', '1', 'a', '23']
new_list = [""]
count = 0
for item in listA:
if count % 4 == 0 and count > 0:
new_list.append("")
new_list[-1] += item
count += 1
listA = new_list
print(listA)
Output:
['stackoverflow12', '3415', '3723', 'L1a23']

Python list insert with index

I have an empty python list. and I have for loop that insert elements with index but at random (means indices are chosen randomly to insert the item). I tried a simple example, with randomly select indices, but it works in some indices but others won't work. Below is a simple example of what I wanna do:
a=[]
#a=[]
a.insert(2, '2')
a.insert(5, '5')
a.insert(0, '0')
a.insert(3, '3')
a.insert(1, '1')
a.insert(4, '4')
The output of this is a = ['0','1','2','5','4','3']
it's correct in the first three (0,1,2) but wrong in the last three ('5','4','3')
How to control insert to an empty list with random indices.
list.insert(i, e) will insert the element e before the index i, so e.g. for an empty list it will insert it as the first element.
Map out the operations in your head using this information:
a = [] # []
a.insert(2, '2') # ['2']
a.insert(5, '5') # ['2', '5']
a.insert(0, '0') # ['0', '2', '5']
a.insert(3, '3') # ['0', '2', '5', '3']
a.insert(1, '1') # ['0', '1', '2', '5', '3']
a.insert(4, '4') # ['0', '1', '2', '5', '4', '3']
Keep in mind that lists are not fixed sized arrays. The list has no predefined size, and can grow and shrink by appending or popping elements.
For what you might want to do you can create a list and use indexing to set the values.
If you know the target size (e.g. it is 6):
a = [None] * 6
a[2] = '2'
# ...
If you only know the maximum possible index, it would have to be done like this:
a = [None] * (max_index+1)
a[2] = '2'
# ...
a = [e for e in a if e is not None] # get rid of the Nones, but maintain ordering
If you do not know the maximum possible index, or it is very large, a list is the wrong data structure, and you could use a dict, like pointed out and shown in the other answers.
If your values are unique, could you use them as keys in a dictionary, with the dict values being the index?
a={}
nums = [1,4,5,7,8,3]
for num in nums:
a.update({str(num): num})
sorted(a, key=a.get)
If you have an empty array and you try to add some element in the third position, that element will be added in first position. Because python's list is a linked list.
You could resolve your problem creating a list with None values in it. This could be made with this:
# Creating a list with size = 10, so you could insert up to 10 elements.
a = [None] * 10
# Inserting the 99 in third position
a.insert(3,99)
Another way to do that is using numpy:
import numpy as np
# Create an empty array with 10 elements
a = np.empty(10,dtype=object)
# Insert 99 number in third position
np.insert(a, 3, 99)
print(a)
# array([None, None, None, 99, None, None, None, None, None, None, None],
# dtype=object)

How to save an element from a list as a whole after an if-statement

I want to save elements of a list as a whole in a new list.
My new task is to transform nested lists into a flat one. My plan was to take out the elements of each list and save them into a variable. And in the end to put the variables together, so that there is just a flat list at the end.
I have two problems:
The index-3 element ('99999') isn't saved as a whole in the list of the new variable. This problem is the topic of this question.
I cannot separate the nested list [66, 77, 88] from the higher list ['4', '5',[]], but this is not the topic of this question
So here is the code of the nested list and of my if statement:
nested_list = ['1', '2', '3', '99999',['4', '5',[66, 77, 88]]]
y = []
for i in nested_list:
if type(i) != (list or tuple):
y += i
print(y)
I want the index=3 element (the string '99999') be saved in the variable y as a whole string and not split into the single parts '9', '9', '9', '9', '9'
I want:
print(y)
['1', '2', '3', '99999']
I get:
print(y)
['1', '2', '3', '9', '9', '9', '9', '9']
I can't solve the problem with saving into a string (y = ' '), because than I get the result:
print(y)
12399999
and if I would transform the string to a list
y = list(y)
I get the same unwanted result
['1', '2', '3', '9', '9', '9', '9', '9']
I think the solution lies in the action code after the if-statement
y += i
Is there a command, which takes the whole element into y? I tried y += sum(i) but of course this didn't work, because
it adds up all numbers like int, floats, etc.., not strings
I don't need to add 9+9+9+9+9=45, but I need just the whole string in my new list y.
I don't know if i understand you right:
# List comprehension:
y = [x for x in nested_list if not isinstance(x, (list, tuple))]
# gives: ['1', '2', '3', '99999']
It would be the same as:
nested_list = ['1', '2', '3', '99999',['4', '5',[66, 77, 88]]]
y = []
for i in nested_list:
if not isinstance(i, (list or tuple)):
y.append(i) # This maybe your failure
print(y)
Does this help you or do you need to have all other elements also in your output list?
(i only recognized your example)
Additional if you want to iterate over all and flatten the whole list:
nested_list = ['1', '2', '3', '99999',['4', '5',[66, 77, 88]]]
y = []
def flatten_list(lst):
if isinstance(lst, (list, tuple)):
if len(lst) == 0:
return []
first, rest = lst[0], lst[1:]
return flatten_list(first) + flatten_list(rest)
else:
return [lst]
y = flatten_list(nested_list)
print(y) # ['1', '2', '3', '99999', '4', '5', 66, 77, 88]
One issue is that (list or tuple) evaluates to a boolean itself, and rather you should use isinstance for type checking
Then, try appending to the list rather than adding stings, which are iterable in themselves. For example, you could've tested [] + '9999' independently for your problem
y = []
for i in nested_list:
if isinstance(i, (list, tuple));
y.append(i)

I want to delete or add the list element when I am browsing it

I want to delete or add the list element when I am browsing it but IndexError: list index out of range
listStep = ['0', '0', '0', '1', '1', '1', '3', '1', '3', '0']
for i in range(0, len(listStep) - 2, 2):
for j in range(i + 2, len(listStep), 2):
if listStep[i + 1] == listStep[j + 1]:
listStep[i] = listStep[i] + listStep[j]
listStep.pop(j)
listStep.pop(j)
print(listStep)
Desired output:
['03', '0', '013', '1']
All advice is not to mutate a list you are iterating through because it is difficult to reason about what happens when you do. Loop through a copy of the list instead using [:].
Typical off by one error, because array indices start at 0 and end at length - 1. I.e. listStep[i + 1]] for i == len(listStep) - 1 (the last value of range()) is len(listStep), i.e. you are accessing one element behind the end of the list.
You are also modifying the list as you process it so len(listStep) changes its value.

Finding the index of the first element of a list in another list

main_list = ['4', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
my_list = ['4', '5', '6']
My question is, how to find index of my_list in main_list?
The integers in my_list must be in consecutive order in main_list.
I tried using main_list.index(my_list[0]) but if there are more than one of a specific element, it returns the wrong index number. The result I need to get is 4, however with main_list.index(my_list[0]) it'll just give 0 as its index.
If there is any need for clarification, I can edit the post with additional details. Sorry, English is not my first language.
Try something like this
for i in range(len(main_list)-len(my_list)):
if main_list[i:i+len(my_list)] == my_list:
index = i
break
This should work for all possible types that could go in the lists.
You can convert both lists into a string using join() function and iteratively compare the strings to find a match.
EDIT: Made a change for it two work for multi-digit numbers. Added a float case as well.
For example:
main_list = ['4', '1', '2', '3', '40.1', '52', '61', '7', '8', '9', '10']
my_list = ['40.1', '52', '61']
index = -1
for i in range(len(main_list)):
if '#'.join(main_list[i:i+len(my_list)]) == '#'.join(my_list):
index = i
break
print(index)
If you would like an algorithm solution:
def Find(haystack, needle):
n, h = len(needle), len(haystack)
assert n <= h
for i in range(h):
if h - i <= n: break
count = 0
for i_, j in zip(range(i, i + n), range(n)):
if haystack[i_] == needle[j]:
count += 1
if count == n: return i
return -1
A much more effective one liner :
print ','.join(main_list).find(','.join(my_list)) - ''.join(main_list).find(''.join(my_list))
Converts them to strings with the elements separated by commas, finds the occurrence, then subtracts the occurrence found when the commas aren't there, and you have your answer.

Categories

Resources