In python, it's called slicing. Here is an example of python's slice notation:
>>> list1 = ['a','b','c','d','e','f','g','h', 'i', 'j', 'k', 'l']
>>> print list1[:5]
['a', 'b', 'c', 'd', 'e']
>>> print list1[-7:]
['f', 'g', 'h', 'i', 'j', 'k', 'l']
Note how you can slice either positively or negatively. When you use a negative number, it means we slice from right to left.
Answer from TerryA on Stack OverflowIn python, it's called slicing. Here is an example of python's slice notation:
>>> list1 = ['a','b','c','d','e','f','g','h', 'i', 'j', 'k', 'l']
>>> print list1[:5]
['a', 'b', 'c', 'd', 'e']
>>> print list1[-7:]
['f', 'g', 'h', 'i', 'j', 'k', 'l']
Note how you can slice either positively or negatively. When you use a negative number, it means we slice from right to left.
Note that you can use a variable in a slice:
l = ['a',' b',' c',' d',' e']
c_index = l.index("c")
l2 = l[:c_index]
This would put the first two entries of l in l2
python - Splitting a list by indexes - Code Review Stack Exchange
Split a list into parts based on a set of indexes in Python - Stack Overflow
python - Splitting a list or list of lists by index - Stack Overflow
python - Splitting a string by list of indices - Stack Overflow
Hello I have a list of integers:
trackIndex = [0, 22, 23, 58, 59,79,80,100,101,122]
These serve as indexes for another list of strings from a text file and I only need to extract certain indexes.
strings = [ "sentence 1", "sentence 2","sentence 3","sentence 4"....]
How can I loop through trackIndex and split it every two indexes (i.e. [0,22], [23,58],[59,79],[80, 100], [101,122] and then take those to extract those indexes from the "strings list" and store it in a new list called "newList"?
There is a lot simpler way to do this. You can use list slicing and the zip function.
List slicing essentially cuts up a given list into sections. The general form is list[start:stop:step]. The start section of a slice designates the first index of the list we want to included in our slice. The stop section designates the first index of the list we want excluded in our slice. The step section defines how many indices we are moving as well as in which direction (based on whether it is positive or negative). An example:
>>> x = [1, 2, 3, 4]
>>> x[1:3]
[2, 3]
>>> x[2:]
[3, 4]
>>> x[0:4]
[1, 2, 3, 4]
>>> x[0:4:1]
[1, 2, 3, 4]
>>> x[0:4:2]
[1, 3]
>>> x[0:4:3]
[1, 4]
>>> x[0:4:4]
[1]
>>> x[0:4:5]
[1]
The zip function takes sequences and creates a zip object that contains tuples of their corresponding index elements:
>>> for pair in zip([1, 2, 3], ['a', 'b', 'c']):
... print(pair)
(1, 'a')
(2, 'b')
(3, 'c')
You can combine these two strategies to simplify your function. Here is my version of your lindexsplit function:
def lindexsplit(some_list, *args):
# Checks to see if any extra arguments were passed. If so,
# prepend the 0th index and append the final index of the
# passed list. This saves from having to check for the beginning
# and end of args in the for-loop. Also, increment each value in
# args to get the desired behavior.
if args:
args = (0,) + tuple(data+1 for data in args) + (len(some_list)+1,)
# For a little more brevity, here is the list comprehension of the following
# statements:
# return [some_list[start:end] for start, end in zip(args, args[1:])]
my_list = []
for start, end in zip(args, args[1:]):
my_list.append(some_list[start:end])
return my_list
A few cosmetic changes to makes your code more beautiful/pythonic :
Fix formatting
- Remove some line breaks as it makes the code harder to read
- Change variables name to follow PEP 8
- Your code lacks documentation making it hard to understand.
Use enumerate
Enumerate does exactly what you are trying to achieve : keep track of the index while looping on an iterable. Just use for indexofitem,item in enumerate(List):.
Remove levels of nested logic
Using elif, you could make your code a bit easier to follow. The inside of the for-loop becomes :
if breakcounter <= numberofbreaks:
if indexofitem < nextbreakindex:
templist1.append(item)
elif breakcounter < (numberofbreaks - 1):
templist1.append(item)
templist2.append(templist1)
templist1 = []
breakcounter +=1
elif indexofitem <= lastindexval and indexofitem <= totalitems:
templist1.append(item)
templist2.append(templist1)
templist1 = []
elif indexofitem >= lastindexval and indexofitem < totalitems + 1:
finalcounter += 1
templist3.append(item)
if finalcounter == finalcounttrigger:
templist2.append(templist3)
Rewrite your comparisons
In Python, you can write comparisons in a very natural way : indexofitem >= lastindexval and indexofitem < totalitems + 1 becomes lastindexval <= indexofitem < totalitems + 1.
Use smart indices to get the last element of array
You can rewrite lastindexval = index[(len(index)-1)] with the much clearer lastindexval = index[-1].
Rethink your logic
You have totalitems = len(List) and indexofitem going from 0 to len(List) - 1 (included). Thus, indexofitem <= totalitems is not an interesting condition to check. The same goes for indexofitem < totalitems + 1.
Once this is removed, we have :
#Less than the last cut
if breakcounter <= numberofbreaks:
if indexofitem < nextbreakindex:
templist1.append(item)
elif breakcounter < (numberofbreaks - 1):
templist1.append(item)
templist2.append(templist1)
templist1 = []
breakcounter +=1
elif indexofitem <= lastindexval:
templist1.append(item)
templist2.append(templist1)
templist1 = []
elif lastindexval <= indexofitem:
finalcounter += 1
templist3.append(item)
if finalcounter == finalcounttrigger:
templist2.append(templist3)
Re-think your logic (bis)
On the code above, the last 2 elif checks are a bit redundant : if we don't go into the indexofitem <= lastindexval block then we must have lastindexval < indexofitem and ``lastindexval <= indexofitem` must be true.
After cleaning this, the code looks like :
for indexofitem,item in enumerate(List):
nextbreakindex = index[breakcounter]
#Less than the last cut
if breakcounter <= numberofbreaks:
if indexofitem < nextbreakindex:
templist1.append(item)
elif breakcounter < (numberofbreaks - 1):
templist1.append(item)
templist2.append(templist1)
templist1 = []
breakcounter +=1
elif indexofitem <= lastindexval:
templist1.append(item)
templist2.append(templist1)
templist1 = []
else:
finalcounter += 1
templist3.append(item)
if finalcounter == finalcounttrigger:
templist2.append(templist3)
return templist2
Re-think your logic (ter)
Nothing happens in the loop if breakcounter > numberofbreaks as breakcounter and numberofbreaks are not changed. If this is really the case, we might as well just break out of the loop. However, things are even better than this : once again we are in a situation that cannot happen. This can be seen in two different ways :
if
breakcounterwas to be bigger thannumberofbreaks,nextbreakindex = index[breakcounter]would have thrown an exception.breakcounteronly gets incremented one element at a time. This happens only ifbreakcounter < (numberofbreaks - 1). Thus, oncebreakcounterreachesnumberofbreaks - 1, it stops growing.
At the end of this rewriting, your code looks like :
def lindexsplit(List,*lindex):
index = list(lindex)
index.sort()
templist1 = []
templist2 = []
templist3 = []
breakcounter = 0
finalcounter = 0
numberofbreaks = len(index)
lastindexval = index[-1]
finalcounttrigger = (len(List)-(lastindexval+1))
for indexofitem,item in enumerate(List):
nextbreakindex = index[breakcounter]
if indexofitem < nextbreakindex:
print "A"
templist1.append(item)
elif breakcounter < (numberofbreaks - 1):
print "B"
templist1.append(item)
templist2.append(templist1)
templist1 = []
breakcounter +=1
elif indexofitem <= lastindexval:
print "C"
templist1.append(item)
templist2.append(templist1)
templist1 = []
else:
print "D"
finalcounter += 1
templist3.append(item)
if finalcounter == finalcounttrigger:
templist2.append(templist3)
return templist2
I reckon there is still a lot more to improve and a much more simple solution could be written (as suggested in the comments).
This is the simplest and most pythonic solution I can think of:
def partition(alist, indices):
return [alist[i:j] for i, j in zip([0]+indices, indices+[None])]
if the inputs are very large, then the iterators solution should be more convenient:
from itertools import izip, chain
def partition(alist, indices):
pairs = izip(chain([0], indices), chain(indices, [None]))
return (alist[i:j] for i, j in pairs)
and of course, the very, very lazy guy solution (if you don't mind to get arrays instead of lists, but anyway you can always revert them to lists):
import numpy
partition = numpy.split
I would be interested in seeing a more Pythonic way of doing this also. But this is a crappy solution. You need to add a checking for an empty index list.
Something along the lines of:
indexes = [5, 12, 17]
list = range(20)
output = []
prev = 0
for index in indexes:
output.append(list[prev:index])
prev = index
output.append(list[indexes[-1]:])
print output
produces
[[0, 1, 2, 3, 4], [5, 6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16], [17, 18, 19]]
s = 'long string that I want to split up'
indices = [0,5,12,17]
parts = [s[i:j] for i,j in zip(indices, indices[1:]+[None])]
returns
['long ', 'string ', 'that ', 'I want to split up']
which you can print using:
print '\n'.join(parts)
Another possibility (without copying indices) would be:
s = 'long string that I want to split up'
indices = [0,5,12,17]
indices.append(None)
parts = [s[indices[i]:indices[i+1]] for i in xrange(len(indices)-1)]
Here is a short solution with heavy usage of the itertools module. The tee function is used to iterate pairwise over the indices. See the Recipe section in the module for more help.
>>> from itertools import tee, izip_longest
>>> s = 'long string that I want to split up'
>>> indices = [0,5,12,17]
>>> start, end = tee(indices)
>>> next(end)
0
>>> [s[i:j] for i,j in izip_longest(start, end)]
['long ', 'string ', 'that ', 'I want to split up']
Edit: This is a version that does not copy the indices list, so it should be faster.