I have a script which imports data and I am storing these in nested lists.
I have one list which instructs how many elements from each sub-list are to be discarded.
How do I do this?
I know how to do it manually, but I want to be able to upload a csv file into my program, and then let it run.
I have run the same line of data twice in csv file to try and make it simpler for me to fix, so I have
starting_index = [203,203]
but in principle this could have a 100 or so elements of different number.
I then have a whole series of nested lists. The number of elements in my starting_index matches the number of sub-lists within each list so at the moment there are only two sub-lists in each nested list.
I wanted to define a function that I could call on to pare each list. I know what is wrong with my code, but I do not know how to make it work.
def index_filter(original_list, new_list):
for i in starting_index:
print(i)
for index, value in enumerate(original_list):
for item,element in enumerate(value):
if item >= i:
new_list[index].append(element)
I realise now that this does not work, and the problems is the
for i in starting_index:
because when it finishes the first element in starting index, it then goes on to the next and appends more data. It doesn't error, but it does not do what I wanted it to do. I just want to remove in this case the first 203 elements from sub-list 1, and the first 203 elements from sub list two, but in principle those numbers will change.
I try and use enumerate all the time, and perhaps it's not appropriate here.
How can I solve this?
Thanks
Edit: Some sample data:
starting_index = [2,1,3]
list_one = [[15,34,67,89,44], [44,23,67,88,45,67,233,567,41,56.4],[45,6734,5,67,29,55,6345,23,89,45,6,8,3,4,5,876]]
ideal result:
list_one = [[67,89,44],[23,67,23,67,88,45,67,233,567,41,56.4],[67,29,55,6345,23,89,45,6,8,3,4,5,876]]
I have just come across the del statement which I am looking at, and I'll also have a look at the slice suggestion. Thanks
Edit: I tried the solution but I can't get it to work.
I tried that but when I put some test data in I get back the original unaltered list.
How do I access the output?
My test script:
original_list=[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], [16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38]]
starting_index=[3,6]
def index_filter(original_list, starting_index):
return [value[i:] for i, value in zip(starting_index, original_list)]
index_filter(original_list, starting_index)
print(index_filter)
print(original_list)
Outputs a strange message and the original unaltered list
<function index_filter at 0x039CC468>
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38]]
Thank you
You need to loop through the starting_index and original_list in parallel, so use zip().
And you can use the slice value[i:] to get the part of a list starting at an index, rather than looping.
def index_filter(original_list, starting_index):
return [value[i:] for i, value in zip(starting_index, original_list)]
original_list=[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], [16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38]]
starting_index=[3,6]
new_list = index_filter(original_list, starting_index)
print(new_list)
Related
I'm trying to create a list of all the prime numbers less than or equal to a given number. I did that successfully using for loops. I was trying to achieve the same using list comprehension using python. But my output has some unexpected values.
Here is my code..
pr=[2]
pr+=[i for i in xrange(3,num+1) if not [x for x in pr if i%x==0]]
where num is the number I had taken as input from user.
The output of the above code for
num=20 is this: [2, 3, 5, 7, 9, 11, 13, 15, 17, 19]
I'm puzzled as to why 9 and 15 are there in the output. What am I doing wrong here?
It simply doesn’t work that way. List comprehensions are evaluated separately, so you can imagine it like this:
pr = [2]
tmp = [i for i in xrange(3,num+1) if not [x for x in pr if i%x==0]]
pr += tmp
By the time tmp is evaluated, pr only contains 2, so you only ever check if a number is divisible by 2 (i.e. if it’s even). That’s why you get all uneven numbers.
You simply can’t solve this nicely† using list comprehensions.
† Not nicely, but ugly and in a very hackish way, by abusing that you can call functions inside a list comprehension:
pr = [2]
[pr.append(i) for i in xrange(3,num+1) if not [x for x in pr if i%x==0]]
print(pr) # [2, 3, 5, 7, 11, 13, 17, 19]
This abuses list comprehensions and basically collects a None value for each prime number you add to pr. So it’s essentially like your normal for loop except that we unnecessarily collect None values in a list… so you should rather allow yourself to use a line break and just use a normal loop.
Your list pr doesn't update until after your entire list comprehension is done. This means your list only contains 2, so every number dividable by 2 is not in the list (as you can see). You should update the list whenever you found a new prime number.
This is because the pr += [...] is evaluated approximately as this:
pr = [2]
tmp = [i for i in xrange(3,num+1) if not [x for x in pr if i%x==0]]
pr.extend(tmp)
So while tmp is generated, contents of pr remains the same ([2]).
I would go with function like this:
>>> import itertools
>>> def primes():
... results = []
... for i in itertools.count(2):
... if all(i%x != 0 for x in results):
... results.append(i)
... yield i
...
# And then you can fetch first 10 primes
>>> list(itertools.islice(primes(), 10))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
# Or get primes smaller than X
>>> list(itertools.takewhile(lambda x: x < 50, primes()))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
Note, that using all is more efficient than creating array and testing whether it's empty.
I am trying to create a list of values that correlate to a string by comparing each character of my string to that of my "alpha_list". This is for encoding procedure so that the numerical values can be added later.
I keep getting multiple errors from numerous different ways i have tried to make this happen.
import string
alpha_list = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"
ints = "HELLO WORLD"
myotherlist = []
for idx, val in enumerate(ints):
myotherlist[idx] = alpha_list.index(val)
print(myotherlist)
Right now this is my current error reading
Traceback (most recent call last):
File "C:/Users/Derek/Desktop/Python/test2.py", line 11, in <module>
myotherlist[idx] = alpha_list.index(val)
IndexError: list assignment index out of range
I am pretty new to python so if I am making a ridiculously obvious mistake please feel free to criticize.
The print(myotherlist) output that i am looking for should look something like this:
[8, 5, 12, 12, 15, 0, 23, 15, 18, 12, 4]
Just use append:
for val in ints:
myotherlist.append(alpha_list.index(val))
print(myotherlist)
myotherlist is an empty list so you cannot access using myotherlist[idx] as there is no element 0 etc..
Or just use a list comprehension:
my_other_list = [alpha_list.index(val) for val in ints]
Or a functional approach using map:
map(alpha_list.index,ints))
Both output:
In [7]: [alpha_list.index(val) for val in ints]
Out[7]: [8, 5, 12, 12, 15, 0, 23, 15, 18, 12, 4]
In [8]: map(alpha_list.index,ints)
Out[8]: [8, 5, 12, 12, 15, 0, 23, 15, 18, 12, 4]
import string - don't use that a bunch of books say its better to use the built in str
myotherlist[idx] = alpha_list.index(val) is why you are getting the error. This is saying 'Go to idx index and put alpha_list.index(val) there, but since the list is empty it cannot do that.
So if you replace
for idx, val in enumerate(ints):
myotherlist[idx] = alpha_list.index(val)
with
for letter in ints: #iterates over the 'HELLO WORLD' string
index_to_append = alpha_list.index(letter)
myotherlist.append(index_to_append)
you will get the expected result!
If there is something not clear please let me know!
I came across a situation where I need to implement a for loop with more than one loop control variable. Basically this is what I am trying to do
Java:
for (int i=0,j=n; i<n,j>=0; i++, j--)
do my stuff
How do I do this in Python?
for i in range(0,n), j in range(n-1,-1,-1):
do my stuff
But this doesn't work. What would be the right syntax here? Also, is there a more elegant(pythonic) construct for the use-case?
For your specific example, it doesn't look like you really need separate variables in the loop definition itself. You can just iterate over the i values and construct the j values by doing n-i:
for i in range(0, n):
j = n-i
# do stuff
In general, you can't specify multiple values in the for statement if they depend on each other. Instead, use the for to iterate over some "base" value or values from which the others can be derived.
You can specify multiple values in the for loop, but they must be drawn from a single iterable:
for i, j in zip(range(0, n), range(n, 0, -1)):
# do stuff
This takes i from the first range (0 to n-1) and j from the second (n to 1). zip creates a new iterable by componentwise pairing the elements of the iterables you give it.
The thing to remember is that Python for loops are not like loops in Java/C, which have an initialize/check end condition/update structure that repeatedly modifies some persistent loop index variable. Python for loops iterate over a "stream" of values provided by a "source" iterable, grabbing one value at a time from the source. (This is similar to foreach-type constructs in some other languages.) Whatever you want to iterate over, you need to get it into an iterable before you begin the loop. In other words, every Python for loop can be thought of as roughly analogous to something like:
for (i=iterable.getNextValue(); iterable.isNotEmpty(); i=iterable.getNextValue())
You can't have the loop initialization be different from the loop update, and you can't have those be any operation other than "get the next value", and you can't have the end condition be anything other than "is the iterable exhausted". If you want to do anything like that, you have to either do it yourself inside the loop (e.g., by assigning a secondary "loop variable" as in my example, or by checking for a custom loop exit condition and breaking out), or build it into the "source" that you're iterating over.
A lot depends on iterators you want. Here's a couple of options. What they have in common is that for... in... will traverse over lists, tuples, and anything else which supports iteration. So you could loop over a list of known values or a generator which produces an arbitrary series of values. The for... in... is the same regardless.
Here's some standard python tricks:
nested loops
for i in range(10):
for j in range (10):
print i, j
This is simple and clear, but for complex iterations it may get very deeply nested. Here range is a generator, which means it produces an iteration over a series (in this case, 10 numbers - but it could be any arbitrary stream of values))
zip
for multiple iterators you can use zip() which creates an iterable object that produces a value from each of several of iterables at the same time. You can use multple assignment inside the for loop to grab pieces out of the zip
a = [1,2,3,4]
b = ['a','b','c','d']
for number, letter in zip (a, b):
print letter, ":", number
# a : 1
# b : 2
# c : 3
# d : 4
zip will stop when the first member is exhausted:
a = [1,2]
b = ['a','b','c','d']
for number, letter in zip (a, b):
print letter, ":", number
# a : 1
# b : 2
zip also uses generators:
test = zip (range(10), range(10,20))
for item in test: print item
#(0, 10)
#(1, 11)
#(2, 12)
#(3, 13)
#(4, 14)
#(5, 15)
#(6, 16)
#(7, 17)
#(8, 18)
#(9, 19)
itertools
For more complex iterations there's a lot of great tools in the itertools module This is particularly nice for things like getting all of the products or permutations of multiple iterators. It's worth checking out but I think it's more than you need
You can create a list comprehension using more than one loop control variable:
>>> n = 10
>>> stuff = [i*j for i in range(n) for j in range(n-1,-1,-1)]
>>> stuff
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 18, 16, 14, 12, 10, 8, 6, 4, 2, 0, 27, 24, 21, 18, 15, 12, 9, 6, 3, 0, 36, 32, 28, 24, 20, 16, 12, 8, 4, 0, 45, 40, 35, 30, 25, 20, 15, 10, 5, 0, 54, 48, 42, 36, 30, 24, 18, 12, 6, 0, 63, 56, 49, 42, 35, 28, 21, 14, 7, 0, 72, 64, 56, 48, 40, 32, 24, 16, 8, 0, 81, 72, 63, 54, 45, 36, 27, 18, 9, 0]
I have a string of numbers that I want to read from a file and parse into sub-sections, with lengths of the subsections based on numbers within the string. The first number in the string is the length of the first sub-section. So for example, if I have a string of data as follows:
4, 11, 22, 33, 3, 44, 55, 5, 44, 55, 66, 77
I want to divide up as follows:
first subsection is length 4, so, 4, 11, 22, 33
second subsection is length 3, so 3, 44, 55
third subsection is length 5, so 5, 44, 55, 66, 77
I tried using variables in slice, so that I could increment the start/stop values as I march through the data, but it doesn't take vars. I worked out a way to delete each subsection as I go so that the first value will always be the length of the next subsection, but it seems sort of clunky.
I'd appreciate any suggestions - thx
You can do something like:
your_list = [4, 11, 22, 33, 3, 44, 55, 5, 44, 55, 66, 77]
subsec = []
it = iter(your_list)
for n in it:
subsec.append([n] + map(lambda x: next(it), range(int(n-1))))
This way you only loop once over your list.
or
for n in it:
subsec.append([n] + [next(it) for _ in range(int(n-1))])
When dealing with more complex logic, I prefer to use regular loops.
In this case I would go with a while loop, running until the list is empty, and removing the elements already processed. If the sections are wrong (i.e. the last section goes beyond the size of the string), the assert will tell you.
sequence = [4, 11, 22, 33, 3, 44, 55, 5, 44, 55, 66, 77]
sections = []
while sequence:
section_size = sequence[0]
assert len(sequence) >= section_size
sections.append(sequence[:section_size])
sequence = sequence[section_size:]
print sections
This splits the sections and save them in a list called sections, with the size as first element, like in your examples.
Edit: added error checking.
Just thought I'd throw this out there. Very similar to both BoppreH's solution, but it avoids the overhead of creating n additional lists by iterating over indices:
def generateSlices(seq):
i = 0
while i < len(seq):
n = x[i]
yield x[i:i + n]
i += n
You can check for errors after generating a list of sublists by doing:
mySubLists = [[5, 23, 33, 44, 2], [10]]
all(len(x) == x[0] for x in mySubLists)
Incidentally, why is your data structured in this strange way? It seems error-prone.
Id like to find a way to see all possible remainders as a list if possible.
as an example instead of 34%5 yielding only 4 i'd like to implement a method that would yield a list of all possible remainders [29, 24, 19, 14, 9,4]
Is this possible?
You can use the range function.
>>> print(list(range(34, 0, -5)))
[34, 29, 24, 19, 14, 9, 4]
(Although only 4 is the remainder. There is only one true remainder.)
Math 101 meets a generator:
def all_remainders(num, denom):
value = num
yield value # we want the original number
while value >= denom:
value -= denom
yield value
Does it work?
>>> list(all_remainders(34, 5))
[34, 29, 24, 19, 14, 9, 4]
>>> list(all_remainders(34, 17))
[34, 17, 0]
>>> _
I hope you understand the logic.
The range-based soluion by #dietrich-epp does the same, just using a standard function.
I'm not sure what exactly did you mean saying about repeated function application; here's my guess. If you want to apply the same function to its own output, you might do something like this:
result = []
for remainder in all_remainders(34, 5):
for nested_remainder in all_remainders(remainder, 3):
result.append(nested_remainder)
print result
But this will print a lot of repeating numbers. You can use a set, and even write the whole thing in one statement (it's called a 'generator comprehension'):
result = set(nested_remainder
for remainder in all_remainders(34, 5)
for nested_remainder in all_remainders(remainder, 7)
)
print result
Too bad the result is not going to be very interesting.
If you explained the problem you're solving, we might come with a better solution.