2.6k

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.

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

|
3.6k

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 đã 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 ra các lát cắt theo chương trình.

|
  • 1

    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.

    – Tạ Thúy Minh 00:13:06 23/09/2013
  • 1

    @RodriKing Có nghĩa là bắt đầu và kết thúc của bạn trống và bước của bạn là -2. Vì vậy, bạn đảo ngược (beause nó âm) và lấy 2 yếu tố, cho toàn bộ danh sách vì bắt đầu và trống không được xác định.

    – Tạ Hạnh Tường 09:54:34 09/08/2018
  • 1

    Một ví dụ khác: a = list(range(100)) # [0,1,2, .... ,99]và điều a[20::-3]đó có nghĩa là bạn sẽ đảo ngược 3 lên 3. Bạn bắt đầu từ vị trí 20 và đi ngược 3 ... 20, 17, 14, v.v ...

    – Hoàng Khắc Thành 09:56:51 09/08/2018
  • 1

    @ mbh86 đó là một ví dụ rất hay! Nó cho thấy rằng dấu hiệu của bước có ưu tiên cho danh sách kết thúc. Tôi đã mong đợi để có được [99, 96, 93, ..., 24, 21].

    – Hồ Gia Bích 10:39:00 31/08/2018
  • 1

    @nodakai: Chuỗi là bất biến; danh sách thì không. b[:]phải là một đối tượng khác với b, nhưng a[:]acó thể giống nhau.

    – Võ Yến Trâm 03:46:09 13/09/2018
467

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

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 một chuỗi ký tự n có chỉ số n .

|
  • 1

    "Một cách để nhớ cách các lát cắt hoạt động là nghĩ về các chỉ số như chỉ giữa các ký tự" - đây là một cách suy nghĩ tuyệt vời về nó

    – Tạ Thảo Nghi 18:05:17 08/08/2018
355

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 `item`
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'
|
257

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ố không 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 lá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 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 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.

|
  • 1

    bạn có thể giải thích cái thứ hai không?

    – Tạ Thảo Nghi 09:10:57 06/07/2018
  • 1

    Điều gì đã xảy ra với phần tử đầu tiên 0, trong danh sách sau khi gán lát đầu tiên? Kết quả của việc r[1:1]=[9,8]nên [0, 9, 8, 1, 2, 3, 4], không phải là nó?

    – Dương Vân Anh 23:14:27 21/11/2018
  • 1

    Rất tiếc, bạn hoàn toàn chính xác, tôi sẽ chỉnh sửa

    – Trịnh Nguyên Sử 00:10:15 23/11/2018
  • 1

    Ban đầu bạn đặt r=[0,1,2,3,4] sau đó thiết lập bạn đặt r[1:1]=[9,8] bây giờ r [0, 9, 8, 1, 2, 3, 4] bây giờ chúng tôi thiết lập r[1:1]=['blah'] và sau đó r nên [0, 'blah', 9, 8, 1, 2, 3, 4]và không[0, 1, 'blah', 9, 8, 2, 3, 4]

    – Tạ Anh Hùng 09:34:31 29/11/2018
  • 1

    Bạn đúng tất nhiên. Một số người khác đã sửa lỗi này gần đây và giới thiệu lỗi; Tôi sẽ hoàn nguyên nó về phiên bản gốc.

    – Lý Quỳnh Châu 17:41:14 30/11/2018
219

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 ký hiệu lát - 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 là đơ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 , 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ó các 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ế stepkhi â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, giá trị 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 máy cắ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 các lát của bạn một 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.

|
133

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]
|
90

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]
|
88

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)
|
54

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 ...

|
39

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 bởi 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'bất chấp 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.

|
  • 1

    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].

    – Bùi Việt Cường 12:56:59 29/10/2016
  • 1

    @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).

    – Đỗ Mỹ Phượng 12:36:59 30/10/2016
33
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

|
  • 1

    Cảm ơn đã liệt kê các chỉ số; Tôi đã nhầm lẫn bởi không có một "-0" nhưng điều này sẽ xóa nó, quyền lực như vậy: D

    – Bùi Việt Cường 03:48:30 18/05/2017
32

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.

|
31

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.
  • Các chỉ số dương 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().

|
28

Đâ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 trong đó phân biệt rõ ràng việc lập chỉ mục và cắt.

Đó là một danh sách với 6 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 2 quả bóng trong 1 hộp hoặc thay thế 2 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ư đối phó với các hộp chính nó. Bạn có thể lấy hộp đầu tiên và đặt nó lên bàn khác. Để chọ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 3 hộp đầu tiên hoặc 2 hộp cuối cùng hoặc tất cả các hộp trong khoảng 1 & 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. Vị trí này được gọi là vị trí bắt đầu và dừng lại.

Đ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 thích.

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 một số lần Bạn cần phải đón một cách riêng biệt. Ví dụ: Bạn có thể chọn mỗi hộp thứ hai. Bạn thậm chí có thể lấy 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 hiện diện đằng sau lát. Vì Python có chức năng sẵn có được gọi là lát, Bạn có thể truyền một số tham số và kiểm tra xem nó tính toán thông số thiếu 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 http://www.avilpage.com/2015/03/a-slice-of-python-intellect-behind.html

|
27

Đâ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]

Xem câu trả lời của abc ở trên

|

Câu trả lời của bạn (> 20 ký tự)

Bằng cách click "Đăng trả lời", bạn đồng ý với Điều khoản dịch vụ, Chính sách bảo mật and Chính sách cookie của chúng tôi.

Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hoặc hỏi câu hỏi của bạn.