简体   繁体   English

Python数组切片—如何实现2D数组切片?

[英]Python array slicing — How can 2D array slicing be implemented?

I am wondering how 2D array slicing can be implemented in Python? 我想知道如何在Python中实现2D数组切片吗?

For example, 例如,

arr is an instance of a self-defined class 2D array. arr是自定义类2D数组的实例。

if I want to enable 2D slicing syntax on this object like this: 如果要在此对象上启用2D切片语法,如下所示:

arr[:,1:3] #retrieve the 1 and 2 column values of every row

or 要么

arr[,:3] #retrieve the 1 and 2 column values of every row

The usage and syntax is just like numpy.array. 用法和语法类似于numpy.array。 But how can this kind of functionality be realized on our own? 但是如何独自实现这种功能呢?

PS: PS:

What I have in mind: 我的想法:

for the first case, the [:,1:3] part is like a tuple of two slices 对于第一种情况, [:,1:3]部分就像两个切片的元组

However, for the second case [,1:3] appears to be quite mysterious. 但是,对于第二种情况, [,1:3]似乎很神秘。

If you want to know the rules of array slicing, the picture below might help: 如果您想了解数组切片的规则,下图可能会有所帮助:

在此处输入图片说明

For read access you need to override the __getitem__ method: 对于读取访问,您需要重写__getitem__方法:

class ArrayLike(object):
    def __init__(self):
        pass
    def __getitem__(self, arg):
        (rows,cols) = arg # unpack, assumes that we always pass in 2-arguments
        # TODO: parse/interpret the rows/cols parameters,
        # for single indices, they will be integers, for slices, they'll be slice objects
        # here's a dummy implementation as a placeholder 
        return numpy.eye(10)[rows, cols]

One of the tricky bits is that __getitem__ always only uses one argument (aside from self), when you put multiple-comma-separated items inside the square brackets, you're actually providing a single tuple as the argument to the __getitem__ call; 棘手的一点是__getitem__总是只使用一个参数(除self之外),当您将多个用逗号分隔的项目放在方括号内时,实际上是在提供一个元组作为__getitem__调用的参数。 thus the need to unpack this tuple (and optionally verify that the length of the tuple is suitable) inside the function. 因此,需要在函数内部拆开该元组的包装(并可选地验证元组的长度合适)。

Now given a = ArrayLike() , you end up with 现在给定a = ArrayLike() ,您最终得到

  • a[2,3] means rows=2 , cols=3 a[2,3]表示rows=2rows=2 cols=3
  • a[:3,2] means rows=slice(None, 3, None) , cols=3 a[:3,2]表示rows=slice(None, 3, None)cols=3

and so on; 等等; you'll have to look at the documentation on slice objects to decide how you want to use the slice information to pull out the data that you need from your class. 您必须查看切片对象文档,以确定如何使用切片信息从类中提取所需的数据。

To make it more like a numpy array, you'd also want to override __setitem__ as well, to allow for assigning to elements/slices. 为了使其更像一个numpy数组,您还希望覆盖__setitem__ ,以允许分配给元素/切片。

obj[,:3] is not valid python so it will raise a SyntaxError -- Therefore, you can't have that syntax in your source file. obj[,:3]是无效的python,因此会引发SyntaxError -因此,您的源文件中不能包含该语法。 (It fails when you try to use it on a numpy array as well) (当您尝试在numpy数组上使用它时,也会失败)

Here is a hack if it's your own class and you are willing to pass in a string. 如果这是您自己的课程,并且愿意传递字符串,这是一种技巧。

How to override the [] operator? 如何重写[]运算符?

class Array(object):

    def __init__(self, m, n):
        """Create junk demo array."""
        self.m = m
        self.n = n
        row = list(range(self.n))
        self.array = map(lambda x:row, range(self.m))

    def __getitem__(self, index_string):
        """Implement slicing/indexing."""

        row_index, _, col_index = index_string.partition(",")

        if row_index == '' or row_index==":":
            row_start = 0
            row_stop = self.m
        elif ':' in row_index:
            row_start, _, row_stop = row_index.partition(":")
            try:
                row_start = int(row_start)
                row_stop = int(row_stop)
            except ValueError:
                print "Bad Data"
        else:
            try:
                row_start = int(row_index)
                row_stop = int(row_index) + 1
            except ValueError:
                print "Bad Data"

        if col_index == '' or col_index == ":":
            col_start = 0
            col_stop = self.n
        elif ':' in col_index:
            col_start, _, col_stop = col_index.partition(":")
            try:
                col_start = int(col_start)
                col_stop = int(col_stop)
            except ValueError:
                print "Bad Data"
        else:
            try:
                col_start = int(col_index)
                col_stop = int(col_index) + 1
            except ValueError:
                print "Bad Data"

        return map(lambda x: self.array[x][col_start:col_stop],
                       range(row_start, row_stop))

    def __str__(self):
        return str(self.array)

    def __repr__(self):
        return str(self.array)


array = Array(4, 5)
print array
out: [[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]

array[",1:3"]
out: [[1, 2], [1, 2], [1, 2], [1, 2]]

array[":,1:3"]
out: [[1, 2], [1, 2], [1, 2], [1, 2]]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM