34

How do I split a list into sub-lists based on index ranges?

e.g. original list:

list1 = [x,y,z,a,b,c,d,e,f,g]

using index ranges 0–4:

list1a = [x,y,z,a,b]

using index ranges 5–9:

list1b = [c,d,e,f,g]

I already known the (variable) indices of list elements which contain certain string and want to split the list based on these index values.

Also need to split into variable number of sub-lists, i.e.:

list1a
list1b
.
.
list1[x]
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
2one
  • 1,035
  • 3
  • 17
  • 36

9 Answers9

22

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.

TerryA
  • 58,805
  • 11
  • 114
  • 143
  • Just for clarity, you can count either positively or negatively, and then either output from that point to the right or that point to the left as in `>>> print(list1[-7:])` or `>>> print(list1[:-7])` (not the position of the colon in both of those examples). And you can also replace the "7" with a variable which would let you (based on knowing the indices) slice the array into as many subarrays as desired. – KJ6BWB Apr 11 '21 at 22:21
19

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

Mark R. Wilkins
  • 1,282
  • 7
  • 15
10

If you already know the indices:

list1 = ['x','y','z','a','b','c','d','e','f','g']
indices = [(0, 4), (5, 9)]
print [list1[s:e+1] for s,e in indices]

Note that we're adding +1 to the end to make the range inclusive...

Jon Clements
  • 138,671
  • 33
  • 247
  • 280
4
list1a=list[:5]
list1b=list[5:]
no1
  • 717
  • 2
  • 8
  • 21
4

One of the ways to do it if you have multiple indexes or know the range of indexes you need to get:

split_points - points where you will split your string or list

k - the range you need to split, example = 3

split_points = [i for i in range(0, len(string), k)]

parts = [string[ind:ind + k] for ind in split_points]
Chris_007
  • 829
  • 11
  • 29
Milana
  • 61
  • 2
2
list1=['x','y','z','a','b','c','d','e','f','g']
find=raw_input("Enter string to be found")
l=list1.index(find)
list1a=[:l]
list1b=[l:]
no1
  • 717
  • 2
  • 8
  • 21
1

Consider the core pesudocode of the following example:

def slice_it(list_2be_sliced, indices):
    """Slices a list at specific indices into constituent lists.
    """
    indices.append(len(list_2be_sliced))
    return [list_2be_sliced[indices[i]:indices[i+1]] for i in range(len(indices)-1)]
Shady
  • 216
  • 2
  • 6
1

This is the way I do it, if the input is a list of indices on which to split an array:

#input
list1 = ['x','y','z','a','b','c','d','e','f','g']
split_points = [2,5,8] 

#split array on indices:
s = split_points+[len(list1)]  #must contain index beyond last element, alternatively use directly split_points.append(len(list1))
print([list1[i1:i2] for i1,i2 in zip([0]+s[:-1],s)])

>>> [['x', 'y'], ['z', 'a', 'b'], ['c', 'd', 'e'], ['f', 'g']]
Vincenzooo
  • 2,013
  • 1
  • 19
  • 33
1

Update May 2023: Option 'fine' integrated.

Update Apr. 2023: Thank you Donna for your comment! I did some changes, like you suggested, but i think that it's a pretty easy example to have more precise information how it works.

The 'slieced' function is maybe a better solution for very long sequencies then the others i saw 'cause you slice the rest of the sequence not the whole again.

It's better to use Sequence_T instead of Sequence 'cause later you can complement the variables with proper commands depending of the sequence-types 'list' or 'tuple' (E.g.: append to a list)

from collections.abc import Sequence
from typing import Iterable, TypeVar

Sequence_T = TypeVar('Sequence_T', bound=Sequence)

def cut(seq: Sequence_T, index: int) -> tuple[Sequence_T, Sequence_T]:
    """ Cut in two slieces. Works with minus-index as well. """
    return seq[:index], seq[index:]

def sliced(seq: Sequence_T, indexes: Iterable[int], fine=False) -> list[Sequence_T]:
    """
    Works like cut in two, but this can sliece the sequence multiple times.
    If you wanna fine sliecies, turn fine=True.
    Then one slice will appear not in a sequence any more.
    Take care of the maximum length of sequence that no empty sequences appear inside the result.
    """

    def checked(a_seq: Sequence_T):
        return a_seq[0] if len(a_seq) == 1 else a_seq

    def as_it_is(a_seq: Sequence_T):
        return a_seq

    if fine:
        f = checked
    else:
        f = as_it_is
    previous_i = 0
    result = []
    for i in indexes:
        seq2 = cut(seq, i-previous_i)
        result.append(f(seq2[0]))
        seq = seq2[1]
        previous_i = i
    result.append(f(seq))
    return result

t = (1, 2, 3, 4, 5)
print(cut(t, 3)) # Output: ((1, 2, 3), (4, 5))
print(sliced(t, (-3,-2))) # Output: [(1, 2), (3,), (4, 5)]
print(sliced(t, (2,3))) # Output: [(1, 2), (3,), (4, 5)]
print(sliced(t, (2,3), True)) # Output: [(1, 2), 3, (4, 5)]
print(sliced(t, t[:-1], True)) # Output: [1, 2, 3, 4, 5]
print(sliced(t, cut(t, -1)[0], True)) # Output: [1, 2, 3, 4, 5]
print(sliced(t, t, True)) # No good output: [1, 2, 3, 4, 5, ()]
        
Practical
  • 11
  • 3
  • This is a nice solution. However it does depend on later versions of Python (>= 3.5). It would also be more helpful with a `from collections.abc import Sequence` statement, and an example – Donna Mar 24 '23 at 23:45
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Donna Mar 24 '23 at 23:45