Shortest way to slice even/odd lines from a python array? - python

Or, a more general question would be, how to slice an array to get every n-th line, so for even/odd you'd want to skip one line, but in the general case you'd want to get every n-th lines, skipping n-1 lines.

Assuming you are talking about a list, you specify the step in the slice (and start index). The syntax is list[start:end:step].
You probably know the normal list access to get an item, e.g. l[2] to get the third item. Giving two numbers and a colon in between, you can specify a range that you want to get from the list. The return value is another list. E.g. l[2:5] gives you the third to sixth item. You can also pass an optional third number, which specifies the step size. The default step size is one, which just means take every item (between start and end index).
Example:
>>> l = range(10)
>>> l[::2] # even - start at the beginning at take every second item
[0, 2, 4, 6, 8]
>>> l[1::2] # odd - start at second item and take every second item
[1, 3, 5, 7, 9]
See lists in the Python tutorial.
If you want to get every n-th element of a list (i.e. excluding the first element), you would have to slice like l[(n-1)::n].
Example:
>>> l = range(20)
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
Now, getting every third element would be:
>>> l[2::3]
[2, 5, 8, 11, 14, 17]
If you want to include the first element, you just do l[::n].

This is more for me as a complete example ;)
>>> import itertools
>>> ret = [[1,2], [3,4,5,6], [7], [8,9]]
>>> itertools.izip_longest(*ret)
>>> [x for x in itertools.chain.from_iterable(tmp) if x is not None]
[1, 3, 7, 8, 2, 4, 9, 5, 6]

example for indices 0,2,4... of myArr
myArr[list(range(0,len(myArr),2))]
example for indices 1,3,5... of myArr
myArr[list(range(1,len(myArr)+1,2))]
you can manipulate it anyway you want with the step parameter, in this case it is equal to 2.
hope this helped

> map(lambda index: arr[index],filter(lambda x: x%n == 0,range(len(arr))))
where arr is a list, and n slices are required.

Related

Getting the value of List and sum in python

I newbie in python and I have a trouble how can I make my loop with that shape below and getting the total number of each line, I tried the code below but it seems it doesn't right
I should use list in loop like the declaration below, I appreciate who can help me.
data = [1, 2, 3, 4, 5]
Expected output:
[1, 2, 3, 4, 5, 15]
[2, 3, 4, 5, 14]
[3, 4, 5, 12]
[4, 5, 9]
[5, 5]
This is what I tried but it doesn't use list ,I think it's wrong
data = 5
for i in range(data):
for j in range(i+1):
print("[",j+1, end=" "+" ]")
print("[ ]")
Usually in these kind of exercises you shouldn't build the string yourself(talking about brackets). Those brackets are part of the representation of the lists in Python. So build your list object and the final result is gonna be printed as you expected. So don't attempt to put individual numbers, spaces, brackets together yourself.
You can use:
data = [1, 2, 3, 4, 5]
for i in range(len(data)):
slice_ = data[i:]
print(slice_ + [sum(slice_)])
Explanation:
Basically in every iteration, you create a slice of the list by specifying the start point to the end. Start point comes from the range(len(data)) range object.
first iteration : From index 0 to end.
second iteration: From index 1 to end.
...
Then you concatenate the slice with the sum of the slice. But you have to put the sum inside a list because a list can't be concatenated with an int. Of course other option is to .append() it before printing:
for i in range(len(data)):
slice_ = data[i:]
slice_.append(sum(slice_))
print(slice_)

splitting a python list in two without needing additional memory

I would like to split an int list l in two small lists l1, l2 (I know the split point n).
I am already able to perform the splitting by copying l2 elements in another list and then removing them from l, but this requires to have space for at least n + n/2 elements in memory and this is not affordable since l is big.
Does someone has a solution?
If you do not want to spend additional memory on the smaller lists, you have two possibilities:
Either you can destroy/reduce the original list as you create the smaller lists. You could use collections.deque, providing O(1) removal and insertion at both ends:
>>> from collections import deque
>>> deq = deque(range(20))
>>> front = deque(deq.popleft() for _ in range(10))
>>> front
deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> deq # original list reduced, can be used as 2nd list
deque([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
Or you can create two views on parts of the smaller lists, meaning that the original list would be altered if the smaller lists are modified, and vice versa. For instance, use numpy.array for your numbers and create slices (being views) on that array:
>>> import numpy as np
>>> arr = np.array(range(20))
>>> front = arr[:10]
>>> back = arr[10:]
>>> front[3] = 100
>>> arr # original list modified
array([ 0, 1, 2, 100, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19])
If you have to use plain Python list, you could also use list.pop. However, as explained in the documentation for deque, you should not use pop(0), as this will have to re-organize the entire list each time you pop an element, giving you O(n²) for extracting half of the list. Instead, use pop() to pop from the end of the list. To restore the original order, you could first pop into a temporary list, and then pop from that list, reversing it twice.
>>> lst = list(range(10))
>>> tmp = [lst.pop() for _ in range(5)]
>>> front, back = lst, [tmp.pop() for _ in range(len(tmp))]
>>> front, back
([0, 1, 2, 3, 4], [5, 6, 7, 8, 9])
You can slice the list with itertools.islice at n. The slice objects are lazy and are only loaded into memory when you iterate on them:
from itertools import islice
def split_list(lst, n):
return islice(lst, n), islice(lst, n, None)
A, B = split_list(range(10), 5)
print(list(A))
# [0, 1, 2, 3, 4]
print(list(B))
# [5, 6, 7, 8, 9]
How about trying this
class mylist(list):
def split_by_position_n(self, n):
return self[:int(n)], self[int(n):]
then, l = mylist(range(1,10))
l.split_by_position_n(4)
>>>([1, 2, 3, 4], [5, 6, 7, 8, 9])
I came with a simple solution. What about
l1 = [l.pop(0) for i in range(n)]
It seems to work and it should not require additional memory.
Helo AreTor,
This is my solution:
list = [1,2,3,4,5,6,7,8,9]
l1 = list[0:n]
l2 = list[n:]
list is the list of elements.
n is the number of elements you want in the first list (the split point index).
list[0:n] will return the first n items of you list.
list[n:] will return the rest of the list.
Hope it helps you
EDIT: If you worry about memory problems, you can delete the list once you split it.. Even you can use list[0:n] / list[n:] in your code and you dont use more memory..

Mysterious interaction between Python's slice bounds and "stride"

I understand that given an iterable such as
>>> it = [1, 2, 3, 4, 5, 6, 7, 8, 9]
I can turn it into a list and slice off the ends at arbitrary points with, for example
>>> it[1:-2]
[2, 3, 4, 5, 6, 7]
or reverse it with
>>> it[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1]
or combine the two with
>>> it[1:-2][::-1]
[7, 6, 5, 4, 3, 2]
However, trying to accomplish this in a single operation produces in some results that puzzle me:
>>> it[1:-2:-1]
[]
>>>> it[-1:2:-1]
[9, 8, 7, 6, 5, 4]
>>>> it[-2:1:-1]
[8, 7, 6, 5, 4, 3]
Only after much trial and error, do I get what I'm looking for:
>>> it[-3:0:-1]
[7, 6, 5, 4, 3, 2]
This makes my head hurt (and can't help readers of my code):
>>> it[-3:0:-1] == it[1:-2][::-1]
True
How can I make sense of this? Should I even be pondering such things?
FWYW, my code does a lot of truncating, reversing, and listifying of iterables, and I was looking for something that was faster and clearer (yes, don't laugh) than list(reversed(it[1:-2])).
This is because in a slice like -
list[start:stop:step]
start is inclusive, resultant list starts at index start.
stop is exclusive, that is the resultant list only contains elements till stop - 1 (and not the element at stop).
So for your caseit[1:-2] - the 1 is inclusive , that means the slice result starts at index 1 , whereas the -2 is exclusive , hence the last element of the slice index would be from index -3.
Hence, if you want the reversed of that, you would have to do it[-3:0:-1] - only then -3 would be included in the sliced result, and the sliced result would go upto 1 index.
The important things to understand in your slices are
Start will be included in the slice
Stop will NOT be included in the slice
If you want to slice backwards, the step value should be a negative value.
Basically the range which you specify is a half-open (half-closed) range.
When you say it[-3:0:-1] you are actually starting from the third element from the back, till we reach 0 (not including zero), step one element at a time backwards.
>>> it[-3:0:-1]
[7, 6, 5, 4, 3, 2]
Instead, you can realize the start value like this
>>> it[len(it)-3 : 0 : -1]
[7, 6, 5, 4, 3, 2]
I think the other two answers disambiguate the usage of slicing and give a clearer image of how its parameters work.
But, since your question also involves readability -- which, let's not forget, is a big factor especially in Python -- I'd like to point out how you can improve it slightly by assigning slice() objects to variables thus removing all those hardcoded : separated numbers.
Your truncate and reverse slice object could, alternatively, be coded with a usage implying name :
rev_slice = slice(-3, 0, -1)
In some other config-like file. You could then use it in its named glory within slicing operations to make this a bit more easy on the eyes :
it[rev_slice] # [7, 6, 5, 4, 3, 2]
This might be a trivial thing to mention, but I think it's probably worth it.
Why not create a function for readability:
def listify(it, start=0, stop=None, rev=False):
if stop is None:
the_list = it[start:]
else:
the_list = it[start:stop]
if rev:
return the_list[::-1]
else:
return the_list
listify(it, start=1, stop=-2) # [2, 3, 4, 5, 6, 7]
listify(it, start=1, stop=-2, rev=True) # [7, 6, 5, 4, 3, 2]
A good way to intuitively understand the Python slicing syntax is to see how it maps to the corresponding C for loop.
A slice like
x[a:b:c]
gives you the same elements as
for (int i = a; i < b; i += c) {
...
}
The special cases are just default values:
a defaults to 0
b defaults to len(x)
c defaults to 1
Plus one more special case:
if c is negative, then a and b are swapped and the < is inverted to a >

Reversing the list in python

In [122]: a = range(10)
In [123]: a[: : -1]
Out[123]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Could you explain the expression a[: : -1]?
a[:] is clearly understandable -> "start form the beginning(space before the colon) and retrieve the list upto the end (space after the colon)"
But I am not getting what the two colons are actually doing in the expression a[: : -1].
A slice takes three arguments, just like range: start, stop and step:
[0, 1, 2, 3, 4, 5][0:4:2] == list(range(0, 4, 2)) # every second element from 0 to 3
The negative step causes the slice to work backwards through the iterable. Without a start and stop (i.e. just the step [::-1]) it starts from the end, as it is working backwards.
The third argument (after two :'s) is the step size. -1 can be interpreted as stepping backwards. In other words, reversing the list.
Try with -2 step size i.e., a[::-2], You'll get:
[9, 7, 5, 3, 1]
Hope this helps.
More elaborate answers and explanations here Explain Python's slice notation

How to append multiple values to a list in Python

I am trying to figure out how to append multiple values to a list in Python. I know there are few methods to do so, such as manually input the values, or put the append operation in a for loop, or the append and extend functions.
However, I wonder if there is a more neat way to do so? Maybe a certain package or function?
You can use the sequence method list.extend to extend the list by multiple values from any kind of iterable, being it another list or any other thing that provides a sequence of values.
>>> lst = [1, 2]
>>> lst.append(3)
>>> lst.append(4)
>>> lst
[1, 2, 3, 4]
>>> lst.extend([5, 6, 7])
>>> lst.extend((8, 9, 10))
>>> lst
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> lst.extend(range(11, 14))
>>> lst
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
So you can use list.append() to append a single value, and list.extend() to append multiple values.
Other than the append function, if by "multiple values" you mean another list, you can simply concatenate them like so.
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> a + b
[1, 2, 3, 4, 5, 6]
If you take a look at the official docs, you'll see right below append, extend. That's what your looking for.
There's also itertools.chain if you are more interested in efficient iteration than ending up with a fully populated data structure.
if the number of items was saved in a variable say n. you can use list comprehension and plus sign for list expansion.
lst = ['A', 'B']
n = 1
new_lst = lst + ['flag'+str(x) for x in range(n)]
print(my_lst)
>>> ['A','B','flag0','flag1']
One way you can work around this type of problem is -
Here we are inserting a list to the existing list by creating a variable new_values.
Note that we are inserting the values in the second index, i.e. a[2]
a = [1, 2, 7, 8]
new_values = [3, 4, 5, 6]
a.insert(2, new_values)
print(a)
But here insert() method will append the values as a list.
So here goes another way of doing the same thing, but this time, we'll actually insert the values in between the items.
a = [1, 2, 7, 8]
a[2:2] = [3,4,5,6]
print(a)

Categories