Hiểu ký hiệu lát


3283

Tôi cần một lời giải thích tốt (tài liệu tham khảo là một điểm cộng) trên ký hiệu lát cắt của Python.

Đối với tôi, ký hiệu này cần một chút để chọn.

Trông nó cực kỳ mạnh mẽ, nhưng tôi không thể nào nghĩ ra được.

Câu trả lời:


4504

Nó thực sự khá đơn giản:

a[start:stop]  # items start through stop-1
a[start:]      # items start through the rest of the array
a[:stop]       # items from the beginning through stop-1
a[:]           # a copy of the whole array

Ngoài ra còn có stepgiá trị, có thể được sử dụng với bất kỳ điều nào ở trên:

a[start:stop:step] # start through not past stop, by step

Điểm quan trọng cần nhớ là :stopgiá trị đại diện cho giá trị đầu tiên không nằm trong lát cắt được chọn. Vì vậy, sự khác biệt giữa stopstartlà số lượng phần tử được chọn (nếu steplà 1, mặc định).

Tính năng khác là starthoặc stopcó thể là số âm , có nghĩa là nó được tính từ cuối mảng thay vì bắt đầu. Vì thế:

a[-1]    # last item in the array
a[-2:]   # last two items in the array
a[:-2]   # everything except the last two items

Tương tự, stepcó thể là một số âm:

a[::-1]    # all items in the array, reversed
a[1::-1]   # the first two items, reversed
a[:-3:-1]  # the last two items, reversed
a[-3::-1]  # everything except the last two items, reversed

Python tốt với lập trình viên nếu có ít mục hơn bạn yêu cầu. Ví dụ: nếu bạn yêu cầu a[:-2]achỉ chứa một yếu tố, bạn sẽ nhận được một danh sách trống thay vì lỗi. Đôi khi bạn muốn lỗi, vì vậy bạn phải biết rằng điều này có thể xảy ra.

Quan hệ với slice()đối tượng

Toán tử cắt []thực sự đang được sử dụng trong đoạn mã trên với một slice()đối tượng sử dụng :ký hiệu (chỉ hợp lệ trong []), tức là:

a[start:stop:step]

tương đương với:

a[slice(start, stop, step)]

Các đối tượng lát cũng hành xử hơi khác nhau tùy thuộc vào số lượng đối số, tương tự range(), tức là cả hai slice(stop)slice(start, stop[, step])được hỗ trợ. Để bỏ qua việc chỉ định một đối số đã cho, người ta có thể sử dụng None, do đó, ví dụ như a[start:]tương đương a[slice(start, None)]hoặc a[::-1]tương đương với a[slice(None, None, -1)].

Mặc dù :ký hiệu dựa trên rất hữu ích cho việc cắt lát đơn giản, việc sử dụng rõ ràng các slice()đối tượng sẽ đơn giản hóa việc tạo chương trình cắt.


122
Cắt các loại dựng sẵn trả về một bản sao nhưng không phổ biến. Đáng chú ý, việc cắt các mảng NumPy trả về một khung nhìn chia sẻ bộ nhớ với bản gốc.
Beni Cherniavsky-Paskin

43
Đây là một câu trả lời đẹp với số phiếu để chứng minh, nhưng nó bỏ lỡ một điều: bạn có thể thay thế Nonecho bất kỳ khoảng trống nào. Ví dụ [None:None]làm cho một bản sao toàn bộ. Điều này hữu ích khi bạn cần chỉ định kết thúc phạm vi bằng một biến và cần bao gồm mục cuối cùng.
Đánh dấu tiền chuộc

6
Điều thực sự làm tôi khó chịu là con trăn nói rằng khi bạn không đặt bắt đầu và kết thúc, chúng mặc định là 0 và độ dài của chuỗi. Vì vậy, theo lý thuyết, khi bạn sử dụng "abcdef" [:: - 1] thì nên chuyển thành "abcdef" [0: 6: -1], nhưng hai biểu thức này không có cùng một đầu ra. Tôi cảm thấy thiếu một cái gì đó trong tài liệu python kể từ khi tạo ra ngôn ngữ.
axell13

6
Và tôi biết rằng "abcdef" [:: - 1] được chuyển thành "abcdef" [6: -7: -1], vì vậy, cách tốt nhất để giải thích sẽ là: hãy để len là độ dài của chuỗi. Nếu bước là dương , mặc định cho bắt đầu và kết thúc là 0 và len . Khác nếu bước là âm , mặc định cho bắt đầu và kết thúc là len và - len - 1.
axell13

4
stackoverflow.com/questions/39241529/ - được đánh dấu là bản sao của điều này, nên sẽ có ý nghĩa khi thêm một phần với delký hiệu lát cắt wrt. Cụ thể, del arr[:]không rõ ràng ngay lập tức ("mảng [:] tạo một bản sao, vì vậy del có xóa bản sao đó không ???" v.v.)
khazhyk

538

Các hướng dẫn Python nói về nó (cuộn xuống một chút cho đến khi bạn nhận được để phần về cắt).

Sơ đồ nghệ thuật ASCII cũng hữu ích cho việc ghi nhớ cách thức hoạt động của các lát:

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
 0   1   2   3   4   5   6
-6  -5  -4  -3  -2  -1

Một cách để nhớ cách các lát cắt hoạt động là nghĩ về các chỉ số là chỉ giữa các ký tự, với cạnh trái của ký tự đầu tiên được đánh số 0. Sau đó, cạnh phải của ký tự cuối cùng của chuỗi n ký tự có chỉ số n .


10
Đề xuất này hoạt động cho bước tiến tích cực, nhưng không cho bước tiến tiêu cực. Từ sơ đồ, tôi mong đợi a[-4,-6,-1]được yPnhưng nó là ty. Điều luôn luôn hoạt động là suy nghĩ trong các ký tự hoặc vị trí và sử dụng lập chỉ mục như một khoảng thời gian nửa mở - mở phải nếu sải chân tích cực, mở trái nếu sải âm.
aguadopd

Nhưng không có cách nào để thu gọn thành một tập hợp trống bắt đầu từ cuối (giống như x[:0]khi bắt đầu từ đầu), vì vậy bạn phải xử lý các mảng nhỏ trong trường hợp đặc biệt. : /
endolith

412

Liệt kê các khả năng được cho phép bởi ngữ pháp:

>>> seq[:]                # [seq[0],   seq[1],          ..., seq[-1]    ]
>>> seq[low:]             # [seq[low], seq[low+1],      ..., seq[-1]    ]
>>> seq[:high]            # [seq[0],   seq[1],          ..., seq[high-1]]
>>> seq[low:high]         # [seq[low], seq[low+1],      ..., seq[high-1]]
>>> seq[::stride]         # [seq[0],   seq[stride],     ..., seq[-1]    ]
>>> seq[low::stride]      # [seq[low], seq[low+stride], ..., seq[-1]    ]
>>> seq[:high:stride]     # [seq[0],   seq[stride],     ..., seq[high-1]]
>>> seq[low:high:stride]  # [seq[low], seq[low+stride], ..., seq[high-1]]

Tất nhiên, nếu (high-low)%stride != 0, thì điểm cuối sẽ thấp hơn một chút high-1.

Nếu stridelà âm, thứ tự được thay đổi một chút kể từ khi chúng tôi đếm ngược:

>>> seq[::-stride]        # [seq[-1],   seq[-1-stride],   ..., seq[0]    ]
>>> seq[high::-stride]    # [seq[high], seq[high-stride], ..., seq[0]    ]
>>> seq[:low:-stride]     # [seq[-1],   seq[-1-stride],   ..., seq[low+1]]
>>> seq[high:low:-stride] # [seq[high], seq[high-stride], ..., seq[low+1]]

Cắt lát mở rộng (có dấu phẩy và dấu chấm lửng) hầu hết chỉ được sử dụng bởi các cấu trúc dữ liệu đặc biệt (như NumPy); các trình tự cơ bản không hỗ trợ chúng.

>>> class slicee:
...     def __getitem__(self, item):
...         return repr(item)
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'

Trên thực tế vẫn còn một cái gì đó còn sót lại, ví dụ nếu tôi gõ 'apple' [4: -4: -1] Tôi nhận được 'elp', python có thể dịch -4 thành 1 không?
liyuan

lưu ý rằng backticks không được ủng hộrepr
wjandrea

@liyuan Kiểu thực hiện __getitem__là; ví dụ của bạn tương đương với apple[slice(4, -4, -1)].
chepner

320

Các câu trả lời ở trên không thảo luận về chuyển nhượng lát. Để hiểu việc gán lát, thật hữu ích khi thêm một khái niệm khác vào nghệ thuật ASCII:

                +---+---+---+---+---+---+
                | P | y | t | h | o | n |
                +---+---+---+---+---+---+
Slice position: 0   1   2   3   4   5   6
Index position:   0   1   2   3   4   5

>>> p = ['P','y','t','h','o','n']
# Why the two sets of numbers:
# indexing gives items, not lists
>>> p[0]
 'P'
>>> p[5]
 'n'

# Slicing gives lists
>>> p[0:1]
 ['P']
>>> p[0:2]
 ['P','y']

Một heuristic là, đối với một lát từ 0 đến n, hãy nghĩ: "số 0 là bắt đầu, bắt đầu từ đầu và lấy n mục trong danh sách".

>>> p[5] # the last of six items, indexed from zero
 'n'
>>> p[0:5] # does NOT include the last item!
 ['P','y','t','h','o']
>>> p[0:6] # not p[0:5]!!!
 ['P','y','t','h','o','n']

Một heuristic khác là, "đối với bất kỳ lát cắt nào, thay thế bắt đầu bằng 0, áp dụng các heuristic trước đó để kết thúc danh sách, sau đó đếm số đầu tiên sao lưu để cắt các mục từ đầu"

>>> p[0:4] # Start at the beginning and count out 4 items
 ['P','y','t','h']
>>> p[1:4] # Take one item off the front
 ['y','t','h']
>>> p[2:4] # Take two items off the front
 ['t','h']
# etc.

Quy tắc đầu tiên của phép gán lát là vì việc cắt trả về một danh sách, phép gán lát yêu cầu một danh sách (hoặc lần lặp khác):

>>> p[2:3]
 ['t']
>>> p[2:3] = ['T']
>>> p
 ['P','y','T','h','o','n']
>>> p[2:3] = 't'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only assign an iterable

Quy tắc thứ hai của phép gán lát, mà bạn cũng có thể thấy ở trên, là bất kỳ phần nào trong danh sách được trả về bằng cách lập chỉ mục lát, đó là phần tương tự được thay đổi bằng phép gán lát:

>>> p[2:4]
 ['T','h']
>>> p[2:4] = ['t','r']
>>> p
 ['P','y','t','r','o','n']

Quy tắc thứ ba của phép gán lát là, danh sách được gán (có thể lặp lại) không phải có cùng độ dài; lát cắt được lập chỉ mục đơn giản là được cắt ra và thay thế hàng loạt bằng bất cứ thứ gì được chỉ định:

>>> p = ['P','y','t','h','o','n'] # Start over
>>> p[2:4] = ['s','p','a','m']
>>> p
 ['P','y','s','p','a','m','o','n']

Phần khó nhất để làm quen là gán cho các lát trống. Sử dụng heuristic 1 và 2, thật dễ dàng để bạn có thể lập chỉ mục cho một lát trống:

>>> p = ['P','y','t','h','o','n']
>>> p[0:4]
 ['P','y','t','h']
>>> p[1:4]
 ['y','t','h']
>>> p[2:4]
 ['t','h']
>>> p[3:4]
 ['h']
>>> p[4:4]
 []

Và sau đó khi bạn đã thấy điều đó, việc gán lát cho lát trống cũng có ý nghĩa:

>>> p = ['P','y','t','h','o','n']
>>> p[2:4] = ['x','y'] # Assigned list is same length as slice
>>> p
 ['P','y','x','y','o','n'] # Result is same length
>>> p = ['P','y','t','h','o','n']
>>> p[3:4] = ['x','y'] # Assigned list is longer than slice
>>> p
 ['P','y','t','x','y','o','n'] # The result is longer
>>> p = ['P','y','t','h','o','n']
>>> p[4:4] = ['x','y']
>>> p
 ['P','y','t','h','x','y','o','n'] # The result is longer still

Lưu ý rằng, vì chúng tôi không thay đổi số thứ hai của lát (4), các mục được chèn luôn xếp chồng lên nhau so với 'o', ngay cả khi chúng tôi đang gán cho lát trống. Vì vậy, vị trí cho phép gán lát trống là phần mở rộng hợp lý của các vị trí cho các phép gán lát không trống.

Sao lưu một chút, điều gì xảy ra khi bạn tiếp tục với đám rước của chúng tôi để bắt đầu lát cắt?

>>> p = ['P','y','t','h','o','n']
>>> p[0:4]
 ['P','y','t','h']
>>> p[1:4]
 ['y','t','h']
>>> p[2:4]
 ['t','h']
>>> p[3:4]
 ['h']
>>> p[4:4]
 []
>>> p[5:4]
 []
>>> p[6:4]
 []

Với việc cắt lát, một khi bạn đã hoàn thành, bạn đã hoàn thành; nó không bắt đầu cắt ngược. Trong Python, bạn không nhận được các bước âm trừ khi bạn yêu cầu rõ ràng bằng cách sử dụng số âm.

>>> p[5:3:-1]
 ['n','o']

Có một số hậu quả kỳ lạ đối với quy tắc "một khi bạn đã hoàn thành, bạn đã hoàn thành":

>>> p[4:4]
 []
>>> p[5:4]
 []
>>> p[6:4]
 []
>>> p[6]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

Trong thực tế, so với việc lập chỉ mục, việc cắt lát Python có khả năng chống lỗi kỳ lạ:

>>> p[100:200]
 []
>>> p[int(2e99):int(1e99)]
 []

Điều này đôi khi có thể có ích, nhưng nó cũng có thể dẫn đến hành vi hơi kỳ lạ:

>>> p
 ['P', 'y', 't', 'h', 'o', 'n']
>>> p[int(2e99):int(1e99)] = ['p','o','w','e','r']
>>> p
 ['P', 'y', 't', 'h', 'o', 'n', 'p', 'o', 'w', 'e', 'r']

Tùy thuộc vào ứng dụng của bạn, điều đó có thể ... hoặc có thể không ... là những gì bạn đang hy vọng ở đó!


Dưới đây là văn bản của câu trả lời ban đầu của tôi. Nó rất hữu ích với nhiều người, vì vậy tôi không muốn xóa nó.

>>> r=[1,2,3,4]
>>> r[1:1]
[]
>>> r[1:1]=[9,8]
>>> r
[1, 9, 8, 2, 3, 4]
>>> r[1:1]=['blah']
>>> r
[1, 'blah', 9, 8, 2, 3, 4]

Điều này cũng có thể làm rõ sự khác biệt giữa cắt và lập chỉ mục.


246

Giải thích ký hiệu lát của Python

Nói tóm lại, các dấu hai chấm ( :) trong ký hiệu subscript ( subscriptable[subscriptarg]) làm cho lát ký hiệu - trong đó có các đối số tùy chọn, start, stop, step:

sliceable[start:stop:step]

Cắt lát Python là một cách nhanh chóng tính toán để truy cập một cách có phương pháp các phần dữ liệu của bạn. Theo tôi, để trở thành một lập trình viên Python trung cấp, đó là một khía cạnh của ngôn ngữ cần phải làm quen.

Định nghĩa quan trọng

Để bắt đầu, hãy xác định một vài thuật ngữ:

start: chỉ mục bắt đầu của lát cắt, nó sẽ bao gồm phần tử tại chỉ mục này trừ khi nó giống như dừng , mặc định là 0, tức là chỉ mục đầu tiên. Nếu nó âm tính, nó có nghĩa là bắt đầu ncác mục từ cuối.

dừng: chỉ mục kết thúc của lát cắt, nó không bao gồm phần tử tại chỉ mục này, mặc định là độ dài của chuỗi được cắt, nghĩa là, lên đến và bao gồm cả kết thúc.

step: số tiền mà chỉ số tăng lên, mặc định là 1. Nếu nó âm, bạn sẽ cắt ngược lại.

Cách lập chỉ mục hoạt động

Bạn có thể thực hiện bất kỳ số nào tích cực hoặc tiêu cực. Ý nghĩa của các số dương rất đơn giản, nhưng đối với các số âm, giống như các chỉ mục trong Python, bạn đếm ngược từ cuối cho bắt đầudừng lại , và đối với bước , bạn chỉ cần giảm chỉ số của mình. Ví dụ này là từ hướng dẫn của tài liệu , nhưng tôi đã sửa đổi nó một chút để chỉ ra mục nào trong chuỗi mỗi tham chiếu chỉ mục:

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
   0   1   2   3   4   5 
  -6  -5  -4  -3  -2  -1

Cách cắt lát hoạt động

Để sử dụng ký hiệu lát cắt với một chuỗi hỗ trợ nó, bạn phải bao gồm ít nhất một dấu hai chấm trong dấu ngoặc vuông theo trình tự (thực sự thực hiện __getitem__phương thức của chuỗi, theo mô hình dữ liệu Python .)

Ký hiệu lát cắt hoạt động như thế này:

sequence[start:stop:step]

Và nhớ lại rằng có những mặc định để bắt đầu , dừngbước , vì vậy để truy cập vào các mặc định, chỉ cần bỏ qua đối số.

Ký hiệu lát để lấy chín phần tử cuối cùng từ một danh sách (hoặc bất kỳ chuỗi nào khác hỗ trợ nó, giống như một chuỗi) sẽ trông như thế này:

my_list[-9:]

Khi tôi thấy điều này, tôi đọc phần trong ngoặc là "thứ 9 từ cuối đến cuối". (Trên thực tế, tôi viết tắt nó là "-9, on")

Giải trình:

Ký hiệu đầy đủ là

my_list[-9:None:None]

và để thay thế mặc định (thực tế steplà khi âm, stopmặc định là -len(my_list) - 1vậy, vì vậy, Nonedừng thực sự chỉ có nghĩa là nó đi đến bất kỳ bước cuối nào đưa nó đến):

my_list[-9:len(my_list):1]

Các thư đại tràng , :là những gì nói với Python bạn đang đem lại cho nó một lát và không phải là một chỉ số thông thường. Đó là lý do tại sao cách tạo thành một bản sao danh sách nông trong Python 2 là

list_copy = sequence[:]

Và xóa chúng là với:

del my_list[:]

(Python 3 có một list.copylist.clearphương thức.)

Khi stepâm, mặc định startstopthay đổi

Theo mặc định, khi stepđối số trống (hoặc None), nó được gán cho +1.

Nhưng bạn có thể chuyển vào một số nguyên âm và danh sách (hoặc hầu hết các phần tử tiêu chuẩn khác) sẽ được cắt từ đầu đến cuối.

Do đó, một lát cắt âm sẽ thay đổi mặc định cho startstop !

Xác nhận điều này trong nguồn

Tôi muốn khuyến khích người dùng đọc nguồn cũng như tài liệu. Các mã nguồn cho các đối tượng lát và logic này được tìm thấy ở đây . Đầu tiên chúng tôi xác định nếu stepâm tính:

 step_is_negative = step_sign < 0;

Nếu vậy, giới hạn dưới -1 có nghĩa là chúng ta cắt tất cả các cách lên đến và bao gồm cả bắt đầu, và giới hạn trên là độ dài trừ đi 1, có nghĩa là chúng ta bắt đầu ở cuối. (Lưu ý rằng ngữ nghĩa của việc này -1khác nhau từ một -1người dùng có thể vượt qua chỉ số bằng Python chỉ mục cuối cùng.)

if (step_is_negative) {
    lower = PyLong_FromLong(-1L);
    if (lower == NULL)
        goto error;

    upper = PyNumber_Add(length, lower);
    if (upper == NULL)
        goto error;
}

Mặt khác steplà dương, và giới hạn dưới sẽ bằng 0 và giới hạn trên (mà chúng ta đi lên nhưng không bao gồm) độ dài của danh sách được cắt.

else {
    lower = _PyLong_Zero;
    Py_INCREF(lower);
    upper = length;
    Py_INCREF(upper);
}

Sau đó, chúng ta có thể cần áp dụng mặc định cho startstop- mặc định sau đó startđược tính là giới hạn trên khi stepâm:

if (self->start == Py_None) {
    start = step_is_negative ? upper : lower;
    Py_INCREF(start);
}

stop, giới hạn dưới:

if (self->stop == Py_None) {
    stop = step_is_negative ? lower : upper;
    Py_INCREF(stop);
}

Đặt cho lát của bạn một cái tên mô tả!

Bạn có thể thấy hữu ích khi tách hình thành lát cắt khỏi việc chuyển nó sang list.__getitem__phương thức ( đó là những gì dấu ngoặc vuông làm ). Ngay cả khi bạn không quen với nó, nó sẽ giữ cho mã của bạn dễ đọc hơn để những người khác có thể phải đọc mã của bạn có thể dễ dàng hiểu những gì bạn đang làm.

Tuy nhiên, bạn không thể chỉ định một số số nguyên được phân tách bằng dấu hai chấm cho một biến. Bạn cần sử dụng đối tượng lát:

last_nine_slice = slice(-9, None)

Đối số thứ hai None, là bắt buộc, để đối số thứ nhất được hiểu là startđối số nếu không nó sẽ là stopđối số .

Sau đó, bạn có thể truyền đối tượng lát vào chuỗi của mình:

>>> list(range(100))[last_nine_slice]
[91, 92, 93, 94, 95, 96, 97, 98, 99]

Thật thú vị khi các phạm vi cũng có các lát:

>>> range(100)[last_nine_slice]
range(91, 100)

Cân nhắc bộ nhớ:

Do các lát của danh sách Python tạo các đối tượng mới trong bộ nhớ, nên một chức năng quan trọng khác cần phải biết là itertools.islice. Thông thường, bạn sẽ muốn lặp lại qua một lát, không chỉ là nó được tạo tĩnh trong bộ nhớ. islicelà hoàn hảo cho việc này. Một báo trước, nó không hỗ trợ lập luận tiêu cực đến start, stophoặc step, vì vậy nếu đó là một vấn đề mà bạn có thể cần phải tính toán các chỉ số hoặc đảo ngược iterable trước.

length = 100
last_nine_iter = itertools.islice(list(range(length)), length-9, None, 1)
list_last_nine = list(last_nine_iter)

và bây giờ:

>>> list_last_nine
[91, 92, 93, 94, 95, 96, 97, 98, 99]

Thực tế là các lát danh sách tạo một bản sao là một tính năng của chính danh sách. Nếu bạn đang cắt các đối tượng nâng cao như Khung dữ liệu Pandas, nó có thể trả về chế độ xem trên bản gốc chứ không phải bản sao.


147

Và một vài điều không rõ ràng ngay lập tức với tôi khi tôi lần đầu tiên nhìn thấy cú pháp cắt lát:

>>> x = [1,2,3,4,5,6]
>>> x[::-1]
[6,5,4,3,2,1]

Cách dễ dàng để đảo ngược trình tự!

Và nếu bạn muốn, vì một số lý do, mỗi mục thứ hai trong chuỗi đảo ngược:

>>> x = [1,2,3,4,5,6]
>>> x[::-2]
[6,4,2]

100

Trong Python 2.7

Cắt lát bằng Python

[a:b:c]

len = length of string, tuple or list

c -- default is +1. The sign of c indicates forward or backward, absolute value of c indicates steps. Default is forward with step size 1. Positive means forward, negative means backward.

a --  When c is positive or blank, default is 0. When c is negative, default is -1.

b --  When c is positive or blank, default is len. When c is negative, default is -(len+1).

Hiểu chỉ định là rất quan trọng.

In forward direction, starts at 0 and ends at len-1

In backward direction, starts at -1 and ends at -len

Khi bạn nói [a: b: c], bạn đang nói tùy thuộc vào dấu của c (tiến hoặc lùi), bắt đầu tại a và kết thúc tại b (không bao gồm phần tử ở chỉ số bth). Sử dụng quy tắc lập chỉ mục ở trên và hãy nhớ rằng bạn sẽ chỉ tìm thấy các yếu tố trong phạm vi này:

-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1

Nhưng phạm vi này tiếp tục theo cả hai hướng vô tận:

...,-len -2 ,-len-1,-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1, len, len +1, len+2 , ....

Ví dụ:

             0    1    2   3    4   5   6   7   8   9   10   11
             a    s    t   r    i   n   g
    -9  -8  -7   -6   -5  -4   -3  -2  -1

Nếu sự lựa chọn của bạn về a, b và c cho phép trùng lặp với phạm vi ở trên khi bạn di chuyển bằng các quy tắc cho a, b, c ở trên, bạn sẽ nhận được một danh sách với các phần tử (được chạm trong khi truyền tải) hoặc bạn sẽ nhận được một danh sách trống.

Một điều cuối cùng: nếu a và b bằng nhau, thì bạn cũng nhận được một danh sách trống:

>>> l1
[2, 3, 4]

>>> l1[:]
[2, 3, 4]

>>> l1[::-1] # a default is -1 , b default is -(len+1)
[4, 3, 2]

>>> l1[:-4:-1] # a default is -1
[4, 3, 2]

>>> l1[:-3:-1] # a default is -1
[4, 3]

>>> l1[::] # c default is +1, so a default is 0, b default is len
[2, 3, 4]

>>> l1[::-1] # c is -1 , so a default is -1 and b default is -(len+1)
[4, 3, 2]


>>> l1[-100:-200:-1] # Interesting
[]

>>> l1[-1:-200:-1] # Interesting
[4, 3, 2]


>>> l1[-1:-1:1]
[]


>>> l1[-1:5:1] # Interesting
[4]


>>> l1[1:-7:1]
[]

>>> l1[1:-7:-1] # Interesting
[3, 2]

>>> l1[:-2:-2] # a default is -1, stop(b) at -2 , step(c) by 2 in reverse direction
[4]

2
một ví dụ thú vị khác: a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]; a[:-2:-2]kết quả là[9]
Deviacium

96

Tìm thấy bảng tuyệt vời này tại http://wiki.python.org/moin/MovingToPythonFromOtherLacular

Python indexes and slices for a six-element list.
Indexes enumerate the elements, slices enumerate the spaces between the elements.

Index from rear:    -6  -5  -4  -3  -2  -1      a=[0,1,2,3,4,5]    a[1:]==[1,2,3,4,5]
Index from front:    0   1   2   3   4   5      len(a)==6          a[:5]==[0,1,2,3,4]
                   +---+---+---+---+---+---+    a[0]==0            a[:-2]==[0,1,2,3]
                   | a | b | c | d | e | f |    a[5]==5            a[1:2]==[1]
                   +---+---+---+---+---+---+    a[-1]==5           a[1:-1]==[1,2,3,4]
Slice from front:  :   1   2   3   4   5   :    a[-2]==4
Slice from rear:   :  -5  -4  -3  -2  -1   :
                                                b=a[:]
                                                b==[0,1,2,3,4,5] (shallow copy of a)

65

Sau khi sử dụng một chút, tôi nhận ra rằng mô tả đơn giản nhất là nó hoàn toàn giống với các đối số trong một forvòng lặp ...

(from:to:step)

Bất kỳ trong số họ là tùy chọn:

(:to:step)
(from::step)
(from:to)

Sau đó, việc lập chỉ mục phủ định chỉ cần bạn thêm độ dài của chuỗi vào các chỉ số phủ định để hiểu nó.

Điều này làm việc cho tôi dù sao ...


52

Tôi thấy dễ dàng hơn để nhớ cách nó hoạt động, và sau đó tôi có thể tìm ra bất kỳ sự kết hợp bắt đầu / dừng / bước cụ thể nào.

Đó là hướng dẫn để hiểu range()đầu tiên:

def range(start=0, stop, step=1):  # Illegal syntax, but that's the effect
    i = start
    while (i < stop if step > 0 else i > stop):
        yield i
        i += step

Bắt đầu từ start, tăng dần theo step, không đạt được stop. Rất đơn giản.

Điều cần nhớ về bước tiêu cực stoplà luôn luôn là kết thúc bị loại trừ, cho dù đó là cao hơn hay thấp hơn. Nếu bạn muốn cùng một lát theo thứ tự ngược lại, sẽ tốt hơn nhiều khi thực hiện đảo ngược một cách riêng biệt: ví dụ: 'abcde'[1:-2][::-1]cắt một char từ trái, hai từ phải, sau đó đảo ngược. (Xem thêm reversed().)

Cắt trình tự là như nhau, ngoại trừ lần đầu tiên nó bình thường hóa các chỉ mục tiêu cực và nó không bao giờ có thể đi ra ngoài trình tự:

TODO : Đoạn mã dưới đây có lỗi với "không bao giờ đi ra ngoài chuỗi" khi abs (bước)> 1; Tôi nghĩ rằng tôi đã vá nó là chính xác, nhưng thật khó hiểu.

def this_is_how_slicing_works(seq, start=None, stop=None, step=1):
    if start is None:
        start = (0 if step > 0 else len(seq)-1)
    elif start < 0:
        start += len(seq)
    if not 0 <= start < len(seq):  # clip if still outside bounds
        start = (0 if step > 0 else len(seq)-1)
    if stop is None:
        stop = (len(seq) if step > 0 else -1)  # really -1, not last element
    elif stop < 0:
        stop += len(seq)
    for i in range(start, stop, step):
        if 0 <= i < len(seq):
            yield seq[i]

Đừng lo lắng về các is Nonechi tiết - chỉ cần nhớ rằng bỏ qua startvà / hoặc stopluôn luôn làm điều đúng đắn để cung cấp cho bạn toàn bộ chuỗi.

Bình thường hóa các chỉ số tiêu cực trước tiên cho phép bắt đầu và / hoặc dừng được tính từ cuối một cách độc lập: 'abcde'[1:-2] == 'abcde'[1:3] == 'bc'mặc dù range(1,-2) == []. Việc chuẩn hóa đôi khi được coi là "modulo độ dài", nhưng lưu ý rằng nó thêm độ dài chỉ một lần: ví dụ: 'abcde'[-53:42]chỉ là toàn bộ chuỗi.


3
this_is_how_slicing_workskhông giống như lát trăn. EG [0, 1, 2][-5:3:3]sẽ nhận được [0] trong python, nhưng list(this_is_how_slicing_works([0, 1, 2], -5, 3, 3))nhận được [1].
Eastsun

@Eastsun Rất tiếc, bạn đã đúng! Một trường hợp rõ ràng hơn: range(4)[-200:200:3] == [0, 3]nhưng list(this_is_how_slicing_works([0, 1, 2, 3], -200, 200, 3)) == [2]. My if 0 <= i < len(seq):là một nỗ lực để thực hiện "không bao giờ đi ra ngoài chuỗi" đơn giản nhưng sai ở bước> 1. Tôi sẽ viết lại nó sau hôm nay (với các bài kiểm tra).
Beni Cherniavsky-Paskin

40

Bản thân tôi sử dụng phương pháp "một chỉ số giữa các yếu tố" để suy nghĩ về nó, nhưng một cách để mô tả nó đôi khi giúp người khác hiểu được điều này là:

mylist[X:Y]

X là chỉ số của phần tử đầu tiên bạn muốn.
Y là chỉ số của yếu tố đầu tiên bạn không muốn.


40
Index:
      ------------>
  0   1   2   3   4
+---+---+---+---+---+
| a | b | c | d | e |
+---+---+---+---+---+
  0  -4  -3  -2  -1
      <------------

Slice:
    <---------------|
|--------------->
:   1   2   3   4   :
+---+---+---+---+---+
| a | b | c | d | e |
+---+---+---+---+---+
:  -4  -3  -2  -1   :
|--------------->
    <---------------|

Tôi hy vọng điều này sẽ giúp bạn lập mô hình danh sách trong Python.

Tham khảo: http://wiki.python.org/moin/MovingToPythonFromOtherLacular


38

Ký hiệu cắt lát Python:

a[start:end:step]
  • Cho startend , các giá trị âm được hiểu là có liên quan đến cuối chuỗi.
  • Chỉ số tích cực cho endbiết vị trí sau phần tử cuối cùng được đưa vào.
  • Các giá trị trống được mặc định như sau : [+0:-0:1].
  • Sử dụng một bước tiêu cực đảo ngược việc giải thích startend

Ký hiệu mở rộng đến ma trận (numpy) và mảng đa chiều. Ví dụ: để cắt toàn bộ cột bạn có thể sử dụng:

m[::,0:2:] ## slice the first two columns

Các lát giữ các tham chiếu, không phải các bản sao của các phần tử mảng. Nếu bạn muốn tạo một bản sao riêng biệt một mảng, bạn có thể sử dụng deepcopy().


34

Bạn cũng có thể sử dụng phép gán lát để loại bỏ một hoặc nhiều thành phần khỏi danh sách:

r = [1, 'blah', 9, 8, 2, 3, 4]
>>> r[1:4] = []
>>> r
[1, 2, 3, 4]

33

Đây chỉ là một số thông tin bổ sung ... Hãy xem xét danh sách dưới đây

>>> l=[12,23,345,456,67,7,945,467]

Vài thủ thuật khác để đảo ngược danh sách:

>>> l[len(l):-len(l)-1:-1]
[467, 945, 7, 67, 456, 345, 23, 12]

>>> l[:-len(l)-1:-1]
[467, 945, 7, 67, 456, 345, 23, 12]

>>> l[len(l)::-1]
[467, 945, 7, 67, 456, 345, 23, 12]

>>> l[::-1]
[467, 945, 7, 67, 456, 345, 23, 12]

>>> l[-1:-len(l)-1:-1]
[467, 945, 7, 67, 456, 345, 23, 12]

33

Đây là cách tôi dạy lát cho người mới:

Hiểu sự khác biệt giữa lập chỉ mục và cắt lát:

Wiki Python có hình ảnh tuyệt vời này phân biệt rõ ràng việc lập chỉ mục và cắt.

Nhập mô tả hình ảnh ở đây

Đó là một danh sách với sáu yếu tố trong đó. Để hiểu rõ hơn về việc cắt lát, hãy xem danh sách đó như một bộ sáu hộp được đặt cùng nhau. Mỗi hộp có một bảng chữ cái trong đó.

Lập chỉ mục giống như xử lý các nội dung của hộp. Bạn có thể kiểm tra nội dung của bất kỳ hộp. Nhưng bạn không thể kiểm tra nội dung của nhiều hộp cùng một lúc. Bạn thậm chí có thể thay thế nội dung của hộp. Nhưng bạn không thể đặt hai quả bóng trong một hộp hoặc thay thế hai quả bóng cùng một lúc.

In [122]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']

In [123]: alpha
Out[123]: ['a', 'b', 'c', 'd', 'e', 'f']

In [124]: alpha[0]
Out[124]: 'a'

In [127]: alpha[0] = 'A'

In [128]: alpha
Out[128]: ['A', 'b', 'c', 'd', 'e', 'f']

In [129]: alpha[0,1]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-129-c7eb16585371> in <module>()
----> 1 alpha[0,1]

TypeError: list indices must be integers, not tuple

Cắt lát giống như tự xử lý các hộp. Bạn có thể lấy hộp đầu tiên và đặt nó lên bàn khác. Để nhận hộp, tất cả những gì bạn cần biết là vị trí bắt đầu và kết thúc của hộp.

Bạn thậm chí có thể chọn ba hộp đầu tiên hoặc hai hộp cuối cùng hoặc tất cả các hộp trong khoảng từ 1 đến 4. Vì vậy, bạn có thể chọn bất kỳ bộ hộp nào nếu bạn biết bắt đầu và kết thúc. Các vị trí này được gọi là vị trí bắt đầu và dừng.

Điều thú vị là bạn có thể thay thế nhiều hộp cùng một lúc. Ngoài ra, bạn có thể đặt nhiều hộp bất cứ nơi nào bạn muốn.

In [130]: alpha[0:1]
Out[130]: ['A']

In [131]: alpha[0:1] = 'a'

In [132]: alpha
Out[132]: ['a', 'b', 'c', 'd', 'e', 'f']

In [133]: alpha[0:2] = ['A', 'B']

In [134]: alpha
Out[134]: ['A', 'B', 'c', 'd', 'e', 'f']

In [135]: alpha[2:2] = ['x', 'xx']

In [136]: alpha
Out[136]: ['A', 'B', 'x', 'xx', 'c', 'd', 'e', 'f']

Cắt lát với Bước:

Cho đến bây giờ bạn đã chọn hộp liên tục. Nhưng đôi khi bạn cần phải nhặt một cách rời rạc. Ví dụ, bạn có thể nhận mỗi hộp thứ hai. Bạn thậm chí có thể nhận mỗi hộp thứ ba từ cuối. Giá trị này được gọi là kích thước bước. Điều này thể hiện khoảng cách giữa các xe bán tải liên tiếp của bạn. Kích thước bước phải là dương nếu bạn chọn hộp từ đầu đến cuối và ngược lại.

In [137]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']

In [142]: alpha[1:5:2]
Out[142]: ['b', 'd']

In [143]: alpha[-1:-5:-2]
Out[143]: ['f', 'd']

In [144]: alpha[1:5:-2]
Out[144]: []

In [145]: alpha[-1:-5:2]
Out[145]: []

Làm thế nào Python tìm ra thông số thiếu:

Khi cắt, nếu bạn bỏ qua bất kỳ tham số nào, Python sẽ tự động tìm ra nó.

Nếu bạn kiểm tra mã nguồn của CPython , bạn sẽ tìm thấy một hàm có tên PySlice_GetIndicesEx () chỉ ra các chỉ số cho một lát cho bất kỳ tham số đã cho nào. Đây là mã tương đương logic trong Python.

Hàm này lấy một đối tượng Python và các tham số tùy chọn để cắt và trả về bắt đầu, dừng, bước và độ dài lát cho lát cắt được yêu cầu.

def py_slice_get_indices_ex(obj, start=None, stop=None, step=None):

    length = len(obj)

    if step is None:
        step = 1
    if step == 0:
        raise Exception("Step cannot be zero.")

    if start is None:
        start = 0 if step > 0 else length - 1
    else:
        if start < 0:
            start += length
        if start < 0:
            start = 0 if step > 0 else -1
        if start >= length:
            start = length if step > 0 else length - 1

    if stop is None:
        stop = length if step > 0 else -1
    else:
        if stop < 0:
            stop += length
        if stop < 0:
            stop = 0 if step > 0 else -1
        if stop >= length:
            stop = length if step > 0 else length - 1

    if (step < 0 and stop >= start) or (step > 0 and start >= stop):
        slice_length = 0
    elif step < 0:
        slice_length = (stop - start + 1)/(step) + 1
    else:
        slice_length = (stop - start - 1)/(step) + 1

    return (start, stop, step, slice_length)

Đây là trí thông minh có mặt đằng sau lát. Vì Python có một hàm tích hợp có tên là lát cắt, bạn có thể truyền một số tham số và kiểm tra xem nó tính toán các tham số bị thiếu một cách thông minh như thế nào.

In [21]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']

In [22]: s = slice(None, None, None)

In [23]: s
Out[23]: slice(None, None, None)

In [24]: s.indices(len(alpha))
Out[24]: (0, 6, 1)

In [25]: range(*s.indices(len(alpha)))
Out[25]: [0, 1, 2, 3, 4, 5]

In [26]: s = slice(None, None, -1)

In [27]: range(*s.indices(len(alpha)))
Out[27]: [5, 4, 3, 2, 1, 0]

In [28]: s = slice(None, 3, -1)

In [29]: range(*s.indices(len(alpha)))
Out[29]: [5, 4]

Lưu ý: Bài viết này ban đầu được viết trong blog của tôi, Sự thông minh đằng sau các lát Python .


29

Theo nguyên tắc chung, viết mã với nhiều giá trị chỉ mục được mã hóa cứng dẫn đến một mớ hỗn độn dễ đọc và bảo trì. Ví dụ, nếu bạn quay lại mã một năm sau đó, bạn sẽ xem nó và tự hỏi bạn đã nghĩ gì khi viết nó. Giải pháp được hiển thị chỉ đơn giản là một cách để nêu rõ hơn mã của bạn đang thực sự làm gì. Nói chung, lát cắt tích hợp () tạo ra một đối tượng lát có thể được sử dụng ở bất cứ nơi nào một lát cắt được cho phép. Ví dụ:

>>> items = [0, 1, 2, 3, 4, 5, 6]
>>> a = slice(2, 4)
>>> items[2:4]
[2, 3]
>>> items[a]
[2, 3]
>>> items[a] = [10,11]
>>> items
[0, 1, 10, 11, 4, 5, 6]
>>> del items[a]
>>> items
[0, 1, 4, 5, 6]

Nếu bạn có một ví dụ s, bạn có thể nhận thêm thông tin về nó bằng cách xem các thuộc tính s.start, s.stop và s.step của nó, tương ứng. Ví dụ:

>>> a = slice(10, 50, 2)
>>> a.start
10
>>> a.stop
50
>>> a.step
2
>>>

25

1. Ký hiệu lát

Để làm cho nó đơn giản, hãy nhớ rằng lát chỉ có một hình thức

s[start:end:step]

và đây là cách nó hoạt động:

  • s: một đối tượng có thể được cắt lát
  • start: chỉ mục đầu tiên để bắt đầu lặp
  • end: chỉ mục cuối cùng, LƯU Ý rằng endchỉ mục sẽ không được bao gồm trong lát kết quả
  • step: chọn phần tử mỗi stepchỉ mục

Một điều nhập khẩu: tất cả start, end, stepcó thể bỏ qua! Và nếu họ bị bỏ qua, giá trị mặc định của họ sẽ được sử dụng: 0, len(s), 1cho phù hợp.

Vì vậy, các biến thể có thể là:

# Mostly used variations
s[start:end]
s[start:]
s[:end]

# Step-related variations
s[:end:step]
s[start::step]
s[::step]

# Make a copy
s[:]

LƯU Ý: Nếu start >= end(chỉ xem xét khi step>0), Python sẽ trả về một lát trống [].

2. Cạm bẫy

Phần trên giải thích các tính năng cốt lõi về cách thức hoạt động của lát và nó sẽ hoạt động trong hầu hết các trường hợp. Tuy nhiên, có thể có những cạm bẫy bạn nên coi chừng, và phần này giải thích chúng.

Chỉ số tiêu cực

Điều đầu tiên khiến người học Python bối rối là một chỉ số có thể âm tính! Đừng hoảng sợ: một chỉ số tiêu cực có nghĩa là đếm ngược.

Ví dụ:

s[-5:]    # Start at the 5th index from the end of array,
          # thus returning the last 5 elements.
s[:-5]    # Start at index 0, and end until the 5th index from end of array,
          # thus returning s[0:len(s)-5].

Bước tiêu cực

Làm cho mọi thứ trở nên khó hiểu hơn cũng stepcó thể là tiêu cực!

Bước tiêu cực có nghĩa là lặp lại mảng ngược: từ đầu đến cuối, với chỉ số kết thúc được bao gồm và chỉ mục bắt đầu được loại trừ khỏi kết quả.

LƯU Ý : khi bước âm, giá trị mặc định startlen(s)(trong khi endkhông bằng 0, vì s[::-1]chứa s[0]). Ví dụ:

s[::-1]            # Reversed slice
s[len(s)::-1]      # The same as above, reversed slice
s[0:len(s):-1]     # Empty list

Lỗi ngoài phạm vi?

Hãy ngạc nhiên: lát cắt không tăng IndexError khi chỉ số nằm ngoài phạm vi!

Nếu chỉ mục nằm ngoài phạm vi, Python sẽ cố gắng hết sức để đặt chỉ mục thành 0hoặc len(s)theo tình huống. Ví dụ:

s[:len(s)+5]      # The same as s[:len(s)]
s[-len(s)-5::]    # The same as s[0:]
s[len(s)+5::-1]   # The same as s[len(s)::-1], and the same as s[::-1]

3. Ví dụ

Hãy kết thúc câu trả lời này bằng các ví dụ, giải thích mọi thứ chúng ta đã thảo luận:

# Create our array for demonstration
In [1]: s = [i for i in range(10)]

In [2]: s
Out[2]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [3]: s[2:]   # From index 2 to last index
Out[3]: [2, 3, 4, 5, 6, 7, 8, 9]

In [4]: s[:8]   # From index 0 up to index 8
Out[4]: [0, 1, 2, 3, 4, 5, 6, 7]

In [5]: s[4:7]  # From index 4 (included) up to index 7(excluded)
Out[5]: [4, 5, 6]

In [6]: s[:-2]  # Up to second last index (negative index)
Out[6]: [0, 1, 2, 3, 4, 5, 6, 7]

In [7]: s[-2:]  # From second last index (negative index)
Out[7]: [8, 9]

In [8]: s[::-1] # From last to first in reverse order (negative step)
Out[8]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

In [9]: s[::-2] # All odd numbers in reversed order
Out[9]: [9, 7, 5, 3, 1]

In [11]: s[-2::-2] # All even numbers in reversed order
Out[11]: [8, 6, 4, 2, 0]

In [12]: s[3:15]   # End is out of range, and Python will set it to len(s).
Out[12]: [3, 4, 5, 6, 7, 8, 9]

In [14]: s[5:1]    # Start > end; return empty list
Out[14]: []

In [15]: s[11]     # Access index 11 (greater than len(s)) will raise an IndexError
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-15-79ffc22473a3> in <module>()
----> 1 s[11]

IndexError: list index out of range

24

Các câu trả lời trước không thảo luận về việc cắt mảng đa chiều có thể sử dụng gói NumPy nổi tiếng :

Cắt lát cũng có thể được áp dụng cho mảng đa chiều.

# Here, a is a NumPy array

>>> a
array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
>>> a[:2, 0:3:2]
array([[1, 3],
       [5, 7]])

" :2" Trước dấu phẩy hoạt động ở chiều thứ nhất và " 0:3:2" sau dấu phẩy hoạt động ở chiều thứ hai.


4
Chỉ cần một lời nhắc nhở thân thiện rằng bạn không thể làm điều này trên Python listmà chỉ có arraytrong Numpy
Mars Lee

15
#!/usr/bin/env python

def slicegraphical(s, lista):

    if len(s) > 9:
        print """Enter a string of maximum 9 characters,
    so the printig would looki nice"""
        return 0;
    # print " ",
    print '  '+'+---' * len(s) +'+'
    print ' ',
    for letter in s:
        print '| {}'.format(letter),
    print '|'
    print " ",; print '+---' * len(s) +'+'

    print " ",
    for letter in range(len(s) +1):
        print '{}  '.format(letter),
    print ""
    for letter in range(-1*(len(s)), 0):
        print ' {}'.format(letter),
    print ''
    print ''


    for triada in lista:
        if len(triada) == 3:
            if triada[0]==None and triada[1] == None and triada[2] == None:
                # 000
                print s+'[   :   :   ]' +' = ', s[triada[0]:triada[1]:triada[2]]
            elif triada[0] == None and triada[1] == None and triada[2] != None:
                # 001
                print s+'[   :   :{0:2d} ]'.format(triada[2], '','') +' = ', s[triada[0]:triada[1]:triada[2]]
            elif triada[0] == None and triada[1] != None and triada[2] == None:
                # 010
                print s+'[   :{0:2d} :   ]'.format(triada[1]) +' = ', s[triada[0]:triada[1]:triada[2]]
            elif triada[0] == None and triada[1] != None and triada[2] != None:
                # 011
                print s+'[   :{0:2d} :{1:2d} ]'.format(triada[1], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]
            elif triada[0] != None and triada[1] == None and triada[2] == None:
                # 100
                print s+'[{0:2d} :   :   ]'.format(triada[0]) +' = ', s[triada[0]:triada[1]:triada[2]]
            elif triada[0] != None and triada[1] == None and triada[2] != None:
                # 101
                print s+'[{0:2d} :   :{1:2d} ]'.format(triada[0], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]
            elif triada[0] != None and triada[1] != None and triada[2] == None:
                # 110
                print s+'[{0:2d} :{1:2d} :   ]'.format(triada[0], triada[1]) +' = ', s[triada[0]:triada[1]:triada[2]]
            elif triada[0] != None and triada[1] != None and triada[2] != None:
                # 111
                print s+'[{0:2d} :{1:2d} :{2:2d} ]'.format(triada[0], triada[1], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]

        elif len(triada) == 2:
            if triada[0] == None and triada[1] == None:
                # 00
                print s+'[   :   ]    ' + ' = ', s[triada[0]:triada[1]]
            elif triada[0] == None and triada[1] != None:
                # 01
                print s+'[   :{0:2d} ]    '.format(triada[1]) + ' = ', s[triada[0]:triada[1]]
            elif triada[0] != None and triada[1] == None:
                # 10
                print s+'[{0:2d} :   ]    '.format(triada[0]) + ' = ', s[triada[0]:triada[1]]
            elif triada[0] != None and triada[1] != None:
                # 11
                print s+'[{0:2d} :{1:2d} ]    '.format(triada[0],triada[1]) + ' = ', s[triada[0]:triada[1]]

        elif len(triada) == 1:
            print s+'[{0:2d} ]        '.format(triada[0]) + ' = ', s[triada[0]]


if __name__ == '__main__':
    # Change "s" to what ever string you like, make it 9 characters for
    # better representation.
    s = 'COMPUTERS'

    # add to this list different lists to experement with indexes
    # to represent ex. s[::], use s[None, None,None], otherwise you get an error
    # for s[2:] use s[2:None]

    lista = [[4,7],[2,5,2],[-5,1,-1],[4],[-4,-6,-1], [2,-3,1],[2,-3,-1], [None,None,-1],[-5,None],[-5,0,-1],[-5,None,-1],[-1,1,-2]]

    slicegraphical(s, lista)

Bạn có thể chạy tập lệnh này và thử nghiệm với nó, dưới đây là một số mẫu mà tôi nhận được từ tập lệnh.

  +---+---+---+---+---+---+---+---+---+
  | C | O | M | P | U | T | E | R | S |
  +---+---+---+---+---+---+---+---+---+
  0   1   2   3   4   5   6   7   8   9   
 -9  -8  -7  -6  -5  -4  -3  -2  -1 

COMPUTERS[ 4 : 7 ]     =  UTE
COMPUTERS[ 2 : 5 : 2 ] =  MU
COMPUTERS[-5 : 1 :-1 ] =  UPM
COMPUTERS[ 4 ]         =  U
COMPUTERS[-4 :-6 :-1 ] =  TU
COMPUTERS[ 2 :-3 : 1 ] =  MPUT
COMPUTERS[ 2 :-3 :-1 ] =  
COMPUTERS[   :   :-1 ] =  SRETUPMOC
COMPUTERS[-5 :   ]     =  UTERS
COMPUTERS[-5 : 0 :-1 ] =  UPMO
COMPUTERS[-5 :   :-1 ] =  UPMOC
COMPUTERS[-1 : 1 :-2 ] =  SEUM
[Finished in 0.9s]

Khi sử dụng bước phủ định, lưu ý rằng câu trả lời được dịch sang phải 1.


14

Bộ não của tôi có vẻ hạnh phúc khi chấp nhận lst[start:end]có chứa startmục thứ. Tôi thậm chí có thể nói rằng đó là một 'giả định tự nhiên'.

Nhưng đôi khi một nghi ngờ len vào và não tôi yêu cầu trấn an rằng nó không chứa endyếu tố thứ.

Trong những khoảnh khắc này, tôi dựa vào định lý đơn giản này:

for any n,    lst = lst[:n] + lst[n:]

Thuộc tính đẹp này cho tôi biết rằng lst[start:end]không chứa endmục -th vì nó nằm tronglst[end:] .

Lưu ý rằng định lý này là đúng cho bất kỳ n. Ví dụ: bạn có thể kiểm tra xem

lst = range(10)
lst[:-42] + lst[-42:] == lst

trả lại True.


12

Theo tôi, bạn sẽ hiểu và ghi nhớ tốt hơn ký hiệu cắt chuỗi Python nếu bạn nhìn vào nó theo cách sau (đọc tiếp).

Hãy làm việc với chuỗi sau ...

azString = "abcdefghijklmnopqrstuvwxyz"

Đối với những người không biết, bạn có thể tạo bất kỳ chuỗi con nào azStringbằng cách sử dụng ký hiệuazString[x:y]

Đến từ các ngôn ngữ lập trình khác, đó là khi ý thức chung bị tổn hại. X và y là gì?

Tôi đã phải ngồi xuống và chạy một số kịch bản trong nhiệm vụ của mình cho một kỹ thuật ghi nhớ sẽ giúp tôi nhớ x và y là gì và giúp tôi cắt chuỗi đúng cách trong lần thử đầu tiên.

Kết luận của tôi là x và y nên được xem là các chỉ số biên bao quanh các chuỗi mà chúng ta muốn thêm. Vì vậy, chúng ta sẽ thấy biểu thức như azString[index1, index2]hoặc thậm chí rõ ràng hơn như azString[index_of_first_character, index_after_the_last_character].

Dưới đây là một ví dụ trực quan về ...

Letters   a b c d e f g h i j ...
         ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
             ┊           ┊
Indexes  0 1 2 3 4 5 6 7 8 9 ...
             ┊           ┊
cdefgh    index1       index2

Vì vậy, tất cả những gì bạn phải làm là đặt index1 và index2 thành các giá trị sẽ bao quanh chuỗi con mong muốn. Chẳng hạn, để có được chuỗi con "cdefgh", bạn có thể sử dụngazString[2:8] , bởi vì chỉ số ở bên trái của "c" là 2 và một ở bên phải kích thước của "h" là 8.

Hãy nhớ rằng chúng tôi đang thiết lập ranh giới. Và những ranh giới đó là những vị trí mà bạn có thể đặt một số dấu ngoặc sẽ được quấn quanh chuỗi con như thế này ...

ab [ cdefgh ] ij

Thủ thuật đó hoạt động mọi lúc và dễ dàng để ghi nhớ.


11

Hầu hết các câu trả lời trước đó sẽ xóa các câu hỏi về ký hiệu lát.

Cú pháp lập chỉ mục mở rộng được sử dụng để cắt là aList[start:stop:step]và các ví dụ cơ bản là:

Nhập mô tả hình ảnh ở đây:

Ví dụ cắt lát khác: 15 lát cắt mở rộng


10

Trong Python, hình thức cơ bản nhất để cắt lát là như sau:

l[start:end]

trong đó lmột số bộ sưu tập, startlà một chỉ mục bao gồm, và endlà một chỉ mục độc quyền.

In [1]: l = list(range(10))

In [2]: l[:5] # First five elements
Out[2]: [0, 1, 2, 3, 4]

In [3]: l[-5:] # Last five elements
Out[3]: [5, 6, 7, 8, 9]

Khi cắt từ đầu, bạn có thể bỏ qua chỉ số 0 và khi cắt đến cuối, bạn có thể bỏ qua chỉ mục cuối cùng vì nó là dự phòng, vì vậy đừng dài dòng:

In [5]: l[:3] == l[0:3]
Out[5]: True

In [6]: l[7:] == l[7:len(l)]
Out[6]: True

Số nguyên âm rất hữu ích khi thực hiện bù trừ so với phần cuối của bộ sưu tập:

In [7]: l[:-1] # Include all elements but the last one
Out[7]: [0, 1, 2, 3, 4, 5, 6, 7, 8]

In [8]: l[-3:] # Take the last three elements
Out[8]: [7, 8, 9]

Có thể cung cấp các chỉ số nằm ngoài giới hạn khi cắt như:

In [9]: l[:20] # 20 is out of index bounds, and l[20] will raise an IndexError exception
Out[9]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [11]: l[-20:] # -20 is out of index bounds, and l[-20] will raise an IndexError exception
Out[11]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Hãy nhớ rằng kết quả của việc cắt một bộ sưu tập là một bộ sưu tập hoàn toàn mới. Ngoài ra, khi sử dụng ký hiệu lát cắt trong các bài tập, độ dài của các phép gán lát không cần phải giống nhau. Các giá trị trước và sau lát cắt được chỉ định sẽ được giữ và bộ sưu tập sẽ thu nhỏ hoặc phát triển để chứa các giá trị mới:

In [16]: l[2:6] = list('abc') # Assigning fewer elements than the ones contained in the sliced collection l[2:6]

In [17]: l
Out[17]: [0, 1, 'a', 'b', 'c', 6, 7, 8, 9]

In [18]: l[2:5] = list('hello') # Assigning more elements than the ones contained in the sliced collection l [2:5]

In [19]: l
Out[19]: [0, 1, 'h', 'e', 'l', 'l', 'o', 6, 7, 8, 9]

Nếu bạn bỏ qua chỉ mục bắt đầu và kết thúc, bạn sẽ tạo một bản sao của bộ sưu tập:

In [14]: l_copy = l[:]

In [15]: l == l_copy and l is not l_copy
Out[15]: True

Nếu các chỉ mục bắt đầu và kết thúc bị bỏ qua khi thực hiện thao tác gán, toàn bộ nội dung của bộ sưu tập sẽ được thay thế bằng một bản sao của những gì được tham chiếu:

In [20]: l[:] = list('hello...')

In [21]: l
Out[21]: ['h', 'e', 'l', 'l', 'o', '.', '.', '.']

Bên cạnh việc cắt lát cơ bản, cũng có thể áp dụng các ký hiệu sau:

l[start:end:step]

trong đó lmột bộ sưu tập, startlà một chỉ mục bao gồm, endlà một chỉ mục độc quyền và steplà một bước tiến có thể được sử dụng để đưa mọi mục thứ n vào l.

In [22]: l = list(range(10))

In [23]: l[::2] # Take the elements which indexes are even
Out[23]: [0, 2, 4, 6, 8]

In [24]: l[1::2] # Take the elements which indexes are odd
Out[24]: [1, 3, 5, 7, 9]

Sử dụng stepcung cấp một mẹo hữu ích để đảo ngược bộ sưu tập trong Python:

In [25]: l[::-1]
Out[25]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

Cũng có thể sử dụng các số nguyên âm cho stepví dụ sau:

In[28]:  l[::-2]
Out[28]: [9, 7, 5, 3, 1]

Tuy nhiên, sử dụng giá trị âm cho stepcó thể trở nên rất khó hiểu. Hơn nữa, để có Pythonic , bạn nên tránh sử dụng start, endsteptrong một lát duy nhất. Trong trường hợp điều này là bắt buộc, hãy xem xét thực hiện điều này trong hai bài tập (một để cắt và một để sải bước).

In [29]: l = l[::2] # This step is for striding

In [30]: l
Out[30]: [0, 2, 4, 6, 8]

In [31]: l = l[1:-1] # This step is for slicing

In [32]: l
Out[32]: [2, 4, 6]

10

Tôi muốn thêm một Hello, World! ví dụ giải thích những điều cơ bản của lát cho những người mới bắt đầu. Nó đã giúp tôi rất nhiều.

Hãy có một danh sách với sáu giá trị ['P', 'Y', 'T', 'H', 'O', 'N']:

+---+---+---+---+---+---+
| P | Y | T | H | O | N |
+---+---+---+---+---+---+
  0   1   2   3   4   5

Bây giờ các lát đơn giản nhất của danh sách đó là danh sách con của nó. Ký hiệu là [<index>:<index>]và chìa khóa là đọc nó như thế này:

[ start cutting before this index : end cutting before this index ]

Bây giờ nếu bạn tạo một lát [2:5]của danh sách trên, điều này sẽ xảy ra:

        |           |
+---+---|---+---+---|---+
| P | Y | T | H | O | N |
+---+---|---+---+---|---+
  0   1 | 2   3   4 | 5

Bạn đã thực hiện cắt trước phần tử có chỉ mục 2và phần khác cắt trước phần tử có chỉ mục 5. Vì vậy, kết quả sẽ là một lát cắt giữa hai lần cắt, một danh sách ['T', 'H', 'O'].


10

Cá nhân tôi nghĩ về nó như một forvòng lặp:

a[start:end:step]
# for(i = start; i < end; i += step)

Ngoài ra, lưu ý rằng các giá trị âm cho startendcó liên quan đến cuối danh sách và được tính toán trong ví dụ trên bởi given_index + a.shape[0].


8

Dưới đây là ví dụ về chỉ mục của chuỗi:

 +---+---+---+---+---+
 | H | e | l | p | A |
 +---+---+---+---+---+
 0   1   2   3   4   5
-5  -4  -3  -2  -1

str="Name string"

Ví dụ cắt lát: [start: end: step]

str[start:end] # Items start through end-1
str[start:]    # Items start through the rest of the array
str[:end]      # Items from the beginning through end-1
str[:]         # A copy of the whole array

Dưới đây là cách sử dụng ví dụ:

print str[0] = N
print str[0:2] = Na
print str[0:7] = Name st
print str[0:7:2] = Nm t
print str[0:-1:2] = Nm ti

5

Nếu bạn cảm thấy các chỉ số tiêu cực trong việc cắt lát là khó hiểu, thì đây là một cách rất dễ để nghĩ về nó: chỉ cần thay thế chỉ số tiêu cực bằng len - index. Vì vậy, ví dụ, thay thế -3 bằng len(list) - 3.

Cách tốt nhất để minh họa những gì cắt lát bên trong chỉ là hiển thị nó trong mã thực hiện thao tác này:

def slice(list, start = None, end = None, step = 1):
  # Take care of missing start/end parameters
  start = 0 if start is None else start
  end = len(list) if end is None else end

  # Take care of negative start/end parameters
  start = len(list) + start if start < 0 else start
  end = len(list) + end if end < 0 else end

  # Now just execute a for-loop with start, end and step
  return [list[i] for i in range(start, end, step)]

4

Kỹ thuật cắt lát cơ bản là xác định điểm bắt đầu, điểm dừng và kích thước bước - còn được gọi là sải chân.

Đầu tiên, chúng tôi sẽ tạo một danh sách các giá trị để sử dụng trong phần cắt của chúng tôi.

Tạo hai danh sách để cắt. Đầu tiên là danh sách số từ 1 đến 9 (Danh sách A). Thứ hai cũng là một danh sách số, từ 0 đến 9 (Danh sách B):

A = list(range(1, 10, 1)) # Start, stop, and step
B = list(range(9))

print("This is List A:", A)
print("This is List B:", B)

Lập chỉ mục số 3 từ A và số 6 từ B.

print(A[2])
print(B[6])

Cắt lát cơ bản

Cú pháp lập chỉ mục mở rộng được sử dụng để cắt là aList [start: stop: step]. Đối số bắt đầu và đối số bước đều mặc định là không - đối số bắt buộc duy nhất là dừng. Bạn có nhận thấy điều này tương tự như cách phạm vi được sử dụng để xác định danh sách A và B không? Điều này là do đối tượng lát đại diện cho tập hợp các chỉ mục được chỉ định bởi phạm vi (bắt đầu, dừng, bước). Tài liệu Python 3,4.

Như bạn có thể thấy, việc xác định chỉ dừng lại trả về một phần tử. Vì bắt đầu mặc định là không, điều này chuyển thành chỉ lấy một phần tử.

Điều quan trọng cần lưu ý, yếu tố đầu tiên là chỉ số 0, không phải chỉ số 1. Đây là lý do tại sao chúng tôi đang sử dụng 2 danh sách cho bài tập này. Các phần tử của List A được đánh số theo vị trí thứ tự (phần tử thứ nhất là 1, phần tử thứ hai là 2, v.v.) trong khi các phần tử của List B là các số sẽ được sử dụng để lập chỉ mục cho chúng ([0] cho phần tử thứ nhất 0, Vân vân.).

Với cú pháp lập chỉ mục mở rộng, chúng tôi lấy một loạt các giá trị. Ví dụ, tất cả các giá trị được lấy bằng dấu hai chấm.

A[:]

Để lấy một tập hợp các phần tử, vị trí bắt đầu và dừng cần được xác định.

Cho mẫu aList [start: stop], lấy hai phần tử đầu tiên từ Danh sách A.


3

Tôi không nghĩ rằng sơ đồ hướng dẫn Python (được trích dẫn trong nhiều câu trả lời khác) là tốt vì đề xuất này hoạt động cho bước tiến tích cực, nhưng không cho bước tiến tiêu cực.

Đây là sơ đồ:

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
 0   1   2   3   4   5   6
-6  -5  -4  -3  -2  -1

Từ sơ đồ, tôi mong đợi a[-4,-6,-1]được yPnhưng nó là ty.

>>> a = "Python"
>>> a[2:4:1] # as expected
'th'
>>> a[-4:-6:-1] # off by 1
'ty'

Điều luôn luôn hoạt động là suy nghĩ trong các ký tự hoặc vị trí và sử dụng lập chỉ mục như một khoảng thời gian nửa mở - mở phải nếu sải chân tích cực, mở trái nếu sải âm.

Bằng cách này, tôi có thể nghĩ a[-4:-6:-1]như a(-6,-4]trong thuật ngữ khoảng.

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
   0   1   2   3   4   5  
  -6  -5  -4  -3  -2  -1

 +---+---+---+---+---+---+---+---+---+---+---+---+
 | P | y | t | h | o | n | P | y | t | h | o | n |
 +---+---+---+---+---+---+---+---+---+---+---+---+
  -6  -5  -4  -3  -2  -1   0   1   2   3   4   5  
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.