Variable not auto incrementing Python - python

I have to classify this list (Lista variable) according to their data type, and the code works as far as I pick a specific [] to classify but the i inside the for and if loops is not augmenting after each loop.
__author__ = 'rodrigocano'
Lista = [55.5,'hola','abc',10,'5','x5',0.25,['A',2,1.5],5,2,5.3,'AEIOU',('perro','gato','pollo'),[1,2,3],1001,['a',1],'mundo','01/10/2015',20080633,'2.5',0.123,(1,2,'A','B')]
lista_clasificable = len(Lista)
def clasificar(lista_clasificable):
for Lista in range(0,len(lista_clasificable)):
i = 0
lista_string = []
lista_int = []
lista_float =[]
lista_tuple = []
lista_list = [] #duh
if type(lista_clasificable[i]) is str:
lista_string.append(lista_clasificable[i])
i += 1
elif type(lista_clasificable[i]) is int:
lista_int.append(lista_clasificable[i])
i += 1
elif type(lista_clasificable[i]) is float:
lista_float.append(lista_clasificable[i])
i += 1
elif type(lista_clasificable[i]) is list :
lista_list.append(lista_clasificable[i])
i += 1
elif type(lista_clasificable[i]) is tuple:
lista_tuple.append(lista_clasificable[i])
i += 1
return 'Su Lista contiente los siguientes ints',lista_int,'Sus Strings son:',lista_string,'Sus floats son:',lista_float,'Sus listas son:',lista_list,'Y Sus tuplas son:',lista_tuple
print(clasificar(Lista))

You're resetting i over and over. It is inside your for loop, so for every item, i is first set to 0. You need to put it before your for loop:
i=0
for Lista in range(0,len(lista_clasificable)):
...
See MSW's comment for your 2nd problem. You are also overwriting the master lists each time, I missed that.
This is pretty un-pythonesque though. Instead of getting the length of the list and using this setup where i tracks the index, just do something like:
for item in Lista:
do something
Python can loop through the list directly - you don't need to use indexing.

You are resetting i to zero at every iteration of the for loop. Put the i=0 above your for loop.

Here's a cleaner version. I am not explaining it in the hopes that you will learn. Ask questions if you can't puzzle it out with the manual at hand. Sorry if I botched the Spanish.
# a little more pythonically and far less repetitious
def classificar(p, types):
# create a dict of lists such that dict[typename] = []
lists = dict()
for t in types:
lists[t.__name__] = []
# for all of the elements in p, assign them to a type list
# if applicable
for x in p:
for t in types:
if type(x) == t:
lists[t.__name__].append(x)
return lists
input = [55.5,'hola','abc',10,'5','x5',0.25,['A',2,1.5],5,2,5.3,'AEIOU',
('perro','gato','pollo'), [1,2,3], 1001, ['a', 1],
'mundo','01/10/2015',20080633,'2.5',0.123,(1,2,'A','B')]
types = [str, int, float, tuple, list]
lists = classificar(input, types)
print('Su lista contiente los siguientes:')
for type in types:
print(' ', type.__name__, lists[type.__name__])

Related

How to handle operating on items in a list without perfectly even len()?

I'm trying to operate on every 5 items in a list, but can't figure out how to handle the remaining items if they don't divide evenly into 5. Right now I'm using modulo, but I can't shake the feeling it's not quite the right answer. Here's an example...
list = ["ValA","ValB","ValC","ValD","ValE","ValF","ValG","ValH","ValI","ValJ","ValK","ValL","ValM","ValN",]
newlist = []
i = 0
for o in list:
i += 1
newlist.append(o)
if i % 5 == 0:
for obj in newlist:
function_for(obj)
newlist.clear()
This code will execute function_for() twice, but not a third time to handle the remaining 4 values. If I add an 'else' statement it runs on every execution.
What's the correct way to handle a situation like this?
This way is pretty easy, if you don't mind modifying the list:
mylist = ["ValA","ValB","ValC","ValD","ValE","ValF","ValG","ValH","ValI","ValJ","ValK","ValL","ValM","ValN",]
while mylist:
function_for( mylist[:5] )
mylist = mylist[5:]
You can also check if the index is equal to the length of the list. (Additionally, it is more idiomatic to use enumerate instead of a counter variable here.)
lst = ["ValA","ValB","ValC","ValD","ValE","ValF","ValG","ValH","ValI","ValJ","ValK","ValL","ValM","ValN",]
newlist = []
for i, o in enumerate(lst, 1):
newlist.append(o)
if i % 5 == 0 or i == len(lst):
print(newlist)
newlist.clear()

How do I add an element to list without adding that element twice in python I have tried this

myUniqueList = []
def add_up():
num = 45,68,95,82,45
if num not in myUniqueList:
myUniqueList.append(num)
add_up()
print (myUniqueList)
Not sure if this is what you want
myUniqueList = []
def add_up():
num = [45,68,95,82,45]
for i in num:
if i not in myUniqueList:
myUniqueList.append(i)
add_up()
print (myUniqueList)
The 'pythonic' way of doing it is using 'set' rather than a list.
A set is a collection that holds unique values - that means you can store a value only once, and if you try to add it again it will be ignored.
The code using sets becomes much more simple:
myUniqueSet = set()
def add_up():
num = [45,68,95,82,45]
for i in num:
myUniqueSet.add(i)
In addition, if you already have the items stored in a list and you would like to just remove duplicate elements, all you will need to do is:
num = [45,68,95,82,45]
mySet = set(num)

How to split a Python array at every occurrence of a given string?

I am making up a code in Python 3.7 in which I need to split an array in chunks.
The array is something similar to the following one:
['1.60500002', '1.61500001', '1.625', '1.63499999','NO',
'1.73500001','1.745', 'NO','2.04500008', '2.05499983']
I am interested to create n different slices (3 in this case) everytime the string 'NO' occurs. Then the output array should be something like:
[['1.60500002', '1.61500001', '1.625', '1.63499999'],
['1.73500001', '1.745'],
['2.04500008', '2.05499983']]
Could someone help me?
You can try iterating through the list, checking if the element is a floating point number and if so adding it to a list and if not creating a new list. Just add up all the lists you've made and that should be it.
def split_str(inp):
array_of_array = []
arr = []
for a in inp:
try:
float(a)
arr.append(a)
except Exception:
array_of_array.append(arr)
arr = []
array_of_array.append(arr)
return array_of_array
loop over the array and if the element is "NO", we split the array until the "NO" element and add it to the output. if we reached the end, the last part would be from the last "NO" to the end.
my_array = ['1.60500002', '1.61500001', '1.625', '1.63499999','NO','1.73500001', '1.745', 'NO','2.04500008', '2.05499983']
output = []
counter = 0
start = 0
for item in my_array:
if item == "NO":
output.append(my_array[start:counter])
start = counter + 1
if counter == len(my_array) - 1:
output.append(my_array[start:counter + 1])
counter += 1
Since the only split indicator is 'NO' this should be easier. All you have to do is check for 'NO' and then create a new list. You also have to handle for the first element scenario as it can be a 'NO' or a number but creation of a new list if it is 'NO' is not required
To create a new list inside a list, you can do examplelist.append([])
Then to access a specific list inside a list, you can mention the list number in square brackets before using append(). eg. examplelist[list_number].append(whatever)
Here is the code I came up with :
#Input
array = ['1.60500002', '1.61500001', '1.625', '1.63499999','NO','1.73500001', '1.745', 'NO','2.04500008', '2.05499983']
#Declaring
result = [] #empty list
list_number = 0 #to access a specific list inside a list
starting_element = True #var to handle starting scenario
for element in array:
#starting scenario
if starting_element:
result.append([])
if element != 'NO':
result[list_number].append(element)
starting_element = False
#NO scenario
elif element == 'NO':
list_number += 1
result.append([])
#Number scenario
elif element != 'NO':
result[list_number].append(element)
print(result)

return a new list that interleaves the two lists but with a twist

def back_interleave(first, second):
if first == [] and second == []:
return []
elif first == []:
return second[::-1]
elif second == []:
return first[::-1]
else:
newlist = []
for i in range(len(first)-1, 0,-1):
newlist.append(first[i])
newlist.append(second[i])
for j in range(len(second)-len(first)-1,0,-1):
newlist.append(second[i])
return newlist
can anybody tells me what's wrong with my code towards this question.
I'm not exactly sure what's wrong with your code, but the second and third if-statements appear to use built-in list reversing functionality which the original problem forbids.
What I would do is determine the length of the longer list, then iterate through both lists backwards.
def back_interleave(first, second):
newlist = []
# You want to iterate through the length of the longer list
length = max(len(first), len(second))
for x in range(length):
# start appending elements from the back of the list
index = -1*(x+1)
if x < len(first):
newlist.append(first[index])
if x < len(second):
newlist.append(second[index])
return newlist
The problem in your code is when you use the range function, the stop value is exclusive i.e., the index 0 is becoming exclusive in your case. And also in the j loop the values at index i are being stored instead of the values at index j.
#CyanideTesla has given the code that works pretty well for your problem

Memoryerror with too big list

I'm writing script in python, and now I have to create pretty big list exactly containing 248956422 integers. The point is, that some of this "0" in this table will be changed for 1,2 or 3, cause I have 8 lists, 4 with beginning positions of genes, and 4 with endings of them.
The point is i have to iterate "anno" several time cause numbers replacing 0 can change with other iteration.
"Anno" has to be written to the file to create annotation file.
Here's my question, how can I divide, or do it on-the-fly , not to get memoryerror including replacing "0" for others, and 1,2,3s for others.
Mabye rewriting the file? I'm waitin for your advice, please ask me if it is not so clear what i wrote :P .
whole_st_gen = [] #to make these lists more clear for example
whole_end_gen = [] # whole_st_gen has element "177"
whole_st_ex = [] # and whole_end_gen has "200" so from position 177to200
whole_end_ex = [] # i need to put "1"
whole_st_mr = [] # of course these list can have even 1kk+ elements
whole_end_mr = [] # note that every st/end of same kind have equal length
whole_st_nc = []
whole_end_nc = [] #these lists are including some values of course
length = 248956422
anno = ['0' for i in range(0,length)] # here i get the memoryerror
#then i wanted to do something like..
for j in range(0, len(whole_st_gen)):
for y in range(whole_st_gen[j],whole_end_gen[j]):
anno[y]='1'
You might be better of by determine the value of each element in anno on the fly:
def anno():
for idx in xrange(248956422):
elm = "0"
for j in range(0, len(whole_st_gen)):
if whole_st_gen[j] <= idx < whole_end_gen[j]:
elm = "1"
for j in range(0, len(whole_st_ex)):
if whole_st_ex[j] <= idx < whole_end_ex[j]:
elm = "2"
for j in range(0, len(whole_st_mr)):
if whole_st_mr[j] <= idx < whole_end_mr[j]:
elm = "3"
for j in range(0, len(whole_st_nc)):
if whole_st_nc[j] <= idx < whole_end_nc[j]:
elm = "4"
yield elm
Then you just iterate using for elm in anno().
I got an edit proposal from the OP suggesting one function for each of whole_*_gen, whole_st_ex and so on, something like this:
def anno_st():
for idx in xrange(248956422):
elm = "0"
for j in range(0, len(whole_st_gen)):
if whole_st_ex[j] <= idx <= whole_end_ex[j]:
elm = "2"
yield elm
That's of course doable, but it will only result in the changes from whole_*_ex applied and one would need to combine them afterwards when writing to file which may be a bit awkward:
for a, b, c, d in zip(anno_st(), anno_ex(), anno_mr(), anno_nc()):
if d != "0":
write_to_file(d)
elif c != "0":
write_to_file(c)
elif b != "0":
write_to_file(b)
else:
write_to_file(a)
However if you only want to apply some of the change sets you could write a function that takes them as parameters:
def anno(*args):
for idx in xrange(248956422):
elm = "0"
for st, end, tag in args:
for j in range(0, len(st)):
if st <= idx < end[j]:
elm = tag
yield tag
And then call by supplying the lists (for example with only the two first changes):
for tag in anno((whole_st_gen, whole_end_gen, "1"),
(whole_st_ex, whole_end_ex, "2")):
write_to_file(tag)
You could use a bytearray object to have a much more compact memory representation than a list of integers:
anno = bytearray(b'\0' * 248956422)
print(anno[0]) # → 0
anno[0] = 2
print(anno[0]) # → 2
print(anno.__sizeof__()) # → 248956447 (on my computer)
Instead of creating a list using list comprehension I suggest to create an iterator using a generator-expression which produce the numbers on demand instead of saving all of them in memory.Also you don't need to use the i in your loop since it's just a throw away variable which you don't use it.
anno = ('0' for _ in range(0,length)) # In python 2.X use xrange() instead of range()
But note that and iterator is a one shot iterable and you can not use it after iterating over it one time.If you want to use it for multiple times you can create N independent iterators from it using itertools.tee().
Also note that you can not change it in-place if you want to change some elements based on a condition you can create a new iterator by iterating over your iterator and applying the condition using a generator expression.
For example :
new_anno =("""do something with i""" for i in anno if #some condition)

Categories