Python list insert with index - python

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)

Related

simpler(save memory) way to get all possible combinations in order of increasing length

I am trying to get all the possible combinations of listA in order of increasing length. This is easy to do, but the current code I have returns Memory error once my list goes above 1000. How do I do the same with a code that does not use as much memory.
original_list = ['1', '2', '3', '4']
#code:
modified_list= [original_list[i:j + 1] for i in range(len(original_list)) for j in range(i + 1, len(original_list))]
print(modified_list)
#output:
#nodified_list = [['1', '2'],['1', '2', '3'],['1', '2', '3', '4'],
['2', '3'],['2', '3', '4'],['3', '4']]
I saw a similar code but this one prints all the combinations of all the elements inside the list.
import itertools
List = []
for L in range(0, len(original_list)+1):
for subset in itertools.combinations(original_list, L):
subset = str(subset).replace('(','[').replace(')',']') #.replace(',','')
List.append(subset)
it's most probably that your modified list that takes up the memory...
try to print the [original_list[i:j + 1] without saving it in another list.
that shouldn't take more memory than your original list size.
Generator expression saves memory a lot, instead of list you can use this:
subsets = (original_list[i:j + 1] for i in range(len(original_list)) for j in range(i + 1, len(original_list)))
Also if you want to print, iterate through each element, do not convert to list.
for i in subsets:
print(i)

Delete even indexes out of range [duplicate]

I'm trying to remove the odd-indexed elements from my list (where zero is considered even) but removing them this way won't work because it throws off the index values.
lst = ['712490959', '2', '623726061', '2', '552157404', '2', '1285252944', '2', '1130181076', '2', '552157404', '3', '545600725', '0']
def remove_odd_elements(lst):
i=0
for element in lst:
if i % 2 == 0:
pass
else:
lst.remove(element)
i = i + 1
How can I iterate over my list and cleanly remove those odd-indexed elements?
You can delete all odd items in one go using a slice:
del lst[1::2]
Demo:
>>> lst = ['712490959', '2', '623726061', '2', '552157404', '2', '1285252944', '2', '1130181076', '2', '552157404', '3', '545600725', '0']
>>> del lst[1::2]
>>> lst
['712490959', '623726061', '552157404', '1285252944', '1130181076', '552157404', '545600725']
You cannot delete elements from a list while you iterate over it, because the list iterator doesn't adjust as you delete items. See Loop "Forgets" to Remove Some Items what happens when you try.
An alternative would be to build a new list object to replace the old, using a list comprehension with enumerate() providing the indices:
lst = [v for i, v in enumerate(lst) if i % 2 == 0]
This keeps the even elements, rather than remove the odd elements.
Since you want to eliminate odd items and keep the even ones , you can use a filter as follows :
>>>filtered_lst=list(filter(lambda x : x % 2 ==0 , lst))
this approach has the overhead of creating a new list.

Remove wildcard string from list

I have a list which is a large recurring dataset with headers of the form:
array = ['header = 1','0','1','2',...,'header = 1','1','2','3',...,'header = 2','1','2','3']
The header string can vary between each individual dataset, but the size of the individual datasets do not.
I would like to remove all of the headers so that I am left with:
array = ['0','1','2',...,'1','2','3',...,'1','2','3']
If the header string does not vary, then I can remove them with:
lookup = array[0]
while True:
try:
array.remove(lookup)
except ValueError:
break
However, if the header strings do change, then they are not caught, and I am left with:
array = ['0','1','2',...,'1','2','3',...,'header = 2','1','2','3']
Is there a way in which the sub-string "header" can be removed, regardless of what else is in the string?
Best use a list comprehension with a condition instead of repeatedly removing elements. Also, use startswith instead of using a fixed lookup to compare to.
>>> array = ['header = 1','0','1','2','header = 1','1','2','3','header = 2','1','2','3']
>>> [x for x in array if not x.startswith("header")]
['0', '1', '2', '1', '2', '3', '1', '2', '3']
Note that this does not modify the existing list but create a new one, but it should be considerably faster as each single remove has O(n) complexity.
If you do not know what the header string is, you can still determine it from the first element:
>>> lookup = array[0].split()[0] # use first part before space
>>> [x for x in array if not x.startswith(lookup)]
['0', '1', '2', '1', '2', '3', '1', '2', '3']
Using the find() method you can determine whether or not the word "header" is contained in the first list item and use that to determine whether or not to remove the first item.

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

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!

Correcting a list with a dictionary and a subsequent .sort() command displays wrong string order

sorry for the bad title. I am new to programming and I could not come up with a better description.
So, I have this code:
umw = {'T':10, 'J':11, 'Q':12, 'K':13, 'A':14}
def card_ranks(ranks):
"Return a list of the ranks, sorted with higher first."
for i in ranks:
if i in umw:
index = ranks.index(i)
ranks[index] = str(umw[i])
ranks.sort(reverse = True)
return ranks
print(card_ranks(['A', '3', '4', 'K'])) #should output [14, 13, 4, 3]
This gives me the following result:
['4', '3', '14', '13']
clearing the "reverse = True" gives the following:
['13', '14', '3', '4']
If i do something like that:
r = card_ranks(['A', '3', '4', 'K'])
r[0] -> gives me '4'
but this doesnt work again:
print(sorted(r)) -> gives me ['4', '3', '14', '13'] all over again.
So it seems, that the .sort() command views the 13 & 14 as a unit and the 3 & 4.
Could somebody explain why that is?
Thanks alot!
You're sorting them lexicographically, as strings rather than numbers. You could convert them to integers first, or you could expand your umw dictionary:
umw = {str(i): i for i in range(2, 10)}
umw.update({'T':10, 'J':11, 'Q':12, 'K':13, 'A':14})
def card_ranks(ranks):
return sorted(ranks, key=umw.get, reverse=True)
card_ranks(['A', '3', '4', 'K'])
# ['A', 'K', '4', '3']
This uses the dict.get method as a key function to guide the sorting without changing the values being sorted.
You are sorting strings where '11' comes before '3'. The following sorted call deals with the necessary type conversion:
def card_ranks(ranks):
return sorted((umw[c] if c in umw else int(c) for c in ranks), reverse=True)
>>> card_ranks(['A', '3', '4', 'K'])
[14, 13, 4, 3]
For every string in ranks, the generator expression produces the corresponding value in the umw dict or, as fallback, turns the string into an int, such that a proper numerical, non-lexicographical comparison is possible.
It does not see them as a unit, it compares the charakter for charakter:
'1'<'3'<'4', so the ranking is '13'<'14'<'3'<'4'
You want all of them to be numbers, so change the following lines:
ranks[index] = str(umw[i])
to
ranks[index] = umw[i]
and:
print(card_ranks(['A', '3', '4', 'K']))
to
print(card_ranks(['A', 3, 4, 'K']))
Because the list elements are string that's why
while sorting its taking in account every character i.e. every digit in the number
Which means every string char is sorted by its first character and then by its next character
Which means "233" < "3" and "1111" < "233"
umw = {'T':10, 'J':11, 'Q':12, 'K':13, 'A':14}
def card_ranks(ranks):
"Return a list of the ranks, sorted with higher first."
for i in ranks:
if i in umw:
index = ranks.index(i)
ranks[index] = str(umw[i])
ranks = list(map(int, ranks)) # The line to be added
ranks.sort(reverse = True)
return ranks
print(card_ranks(['A', '3', '4', 'K'])) #sh
You need to convert the list elements to int by ranks = list(map(int, ranks)) before sorting the list
ranks[index] = str(umw[i])
You are saving the values as strings instead of integers. And it is sorting them as strings.
Try
ranks[index] = int(umw[i])

Categories

Resources