2

I have array2D = [[1,2,3],[4,5,6]]. What I want is a function which takes an index and returns the elements in 1D array.

Example: fn(0) -> returns [1,4]
         fn{1) -> returns [2,5]

I need a fast way to do this.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
tsadkan yitbarek
  • 1,360
  • 2
  • 11
  • 28

5 Answers5

3

you can use lambda and list comprehension:

array2D = [[1,2,3],[4,5,6]]

fn = lambda x: [item[x] for item in array2D]

print(fn(0)) # [1, 4]
print(fn(1)) # [2, 5]
print(fn(2)) # [3, 6]

as suggested in the comments, you may apply the same concept with a function definition:

def fn(x): return [item[x] for item in array2D]

print(fn(0)) # [1, 4]
print(fn(1)) # [2, 5]
print(fn(2)) # [3, 6]

Lambda functions are pretty useful, and let you define operation in a really clear way.
In our example, our lambda accept a variable x, which represent the index we want of each item in array2D

Then you have list comprehension, similarly to lambda function, they are a really powerful tool and a must in python

In this situation you should prefear the function definiton, as suggested by PEP-8.

Gsk
  • 2,929
  • 5
  • 22
  • 29
  • Can you explain why (if it all) lambda functions are clearer than regular functions? IMO, this is an unnecessary extra function call. – jpp Aug 03 '18 at 08:49
  • @jpp I did not say that lambda function are clearer than regular functions. I said that lambda function are really clear: usually because the concision needed to define the operation in one line requires to have a clear understanding of the problem. Of course, we can complicate anything, if we want – Gsk Aug 03 '18 at 08:52
  • OK, it seems like `lambda` is, in fact, _complicating_ matters. Why not `def fn(x): return [item[x] for item in array2D]`? Still one line. And less characters (if it matters). – jpp Aug 03 '18 at 08:53
  • @jpp how it is complicating matters? – Gsk Aug 03 '18 at 08:58
  • If you _really_ want a function to return a function for such a generic task, use `functools.partial`, see my update. – jpp Aug 03 '18 at 09:08
  • @jpp I just actually find out that [PEP-8](https://www.python.org/dev/peps/pep-0008/#programming-recommendations) discourage assigning lambda directly to an identifier. For your example, I don't get why you rely on some imports: is there a substantial improvement to justify that? – Gsk Aug 03 '18 at 09:11
  • Well, *in my opinion* anything in the [standard library](https://docs.python.org/3/library/) should be considered a "free" import. Things have moved in and out of standard library, it shouldn't determine whether they are good to use. – jpp Aug 03 '18 at 09:12
1

The following list comprehension will work:

def fn(i, lst):
    return [sublst[i] for sublst in lst]

>>> array2D = [[1, 2, 3], [4, 5, 6]]
>>> fn(0, array2D)
[1, 4]
>>> fn(1, array2D)
[2, 5]
user2390182
  • 72,016
  • 6
  • 67
  • 89
1

You can use operator.itemgetter:

array2D = [[1,2,3],[4,5,6]]

from operator import itemgetter

def fn(x, k):
    return list(map(itemgetter(k), x))

fn(array2D, 0)  # [1, 4]

If you want to define new functions for retrieving a specific index, you can do so via functools.partial:

from functools import partial

def fn(x, k):
    return list(map(itemgetter(k), x))

get_zero_index = partial(fn, k=0)
get_zero_index(array2D)  # [1, 4]
jpp
  • 159,742
  • 34
  • 281
  • 339
0

How about a generator?

We could use zip to pack them, then create a empty list to store the generated data:

class myZip(object):
    __slots__ = ('zipData', 'interList')

    def __init__(self, *args):
        self.zipData = zip(*args)
        self.interList = []

    def __call__(self, index):
        try:
            return self.interList[index]
        except IndexError:
            try:
                if index == 0:
                    self.interList.append(next(self.zipData))
                    return self.interList[index]
                for i in range(index-(len(self.interList)-1)):
                    self.interList.append(next(self.zipData))
                return self.interList[index]
            except StopIteration:
                raise IndexError("index out of range")

    def __iter__(self):
        for i in self.interList:
            yield i

        for i in self.zipData:
            yield i

array2D = [[1,2,3],[4,5,6]]

a = myZip(*array2D)

print(a(2))
print(a(1))
print(a(0))
---
(3, 6)
(2, 5)
(1, 4)

The benefits of this is we do not need to produce all data at once.

Cyrbuzz
  • 119
  • 1
  • 8
0

Here are my two cents using slicing (I have to use additional np.array() for this because your original data was a list):

array2D = np.array([[1,2,3],[4,5,6]])

def fn(n): return (list(array2D[:,n]))

print (fn(0), fn(1), fn(2))
Sheldore
  • 37,862
  • 7
  • 57
  • 71