简体   繁体   中英

How to convert neatly 1 size numpy array to a scalar? Numpy “asscalar” gives error when input is not a 1 size array.

I have this silly interest in how to avoid the following error in a smart way (possibly using the right numpy functions).

In many ocasions I need to use the numpy where function to find a single item. However, sometimes this item is present more than once, I would like to use the indeces from the where function in a way in which the output would be an simple variable (if it appears once, either string or float) or an array (if mutiple instances).

Of course, I could use len() in a boolean check and perform the conversion. However, I would like to know if there is a one step approach. I had tought to use asscalar however, this function returns and error if the input is not a 1 value array (I had hope it would return the input value unchanged :/). Here is the reproduction of the error on the second part of the code

import numpy as np

Inventory   = np.array(['Eggs', 'Milk', 'Ham', 'Eggs'])
Drinks      = 'Milk'
Food        = 'Eggs'

index_item_searched = np.where(Inventory == Drinks)
items_instore = np.asscalar(Inventory[index_item_searched])
print 'The shop has', items_instore

index_item_store = np.where(Inventory == Food)
items_instore = np.asscalar(Inventory[index_item_store])
print 'The shop has', items_instore
#I want an output like ['Eggs', 'Eggs']

Thanks for your patience :)

If I understand correctly that you want to print a scalar in case of a single find in the Inventory , while you want to print an array in case of multiple finds, then the answer is " this is not a nice thing to do ", and is generally considered poor design. In other words, there's a reason why this can't be done without a bit of work: it can be dangerous if your code produces different kinds of results based on semantics.

Anyway, one of the answers by @kindall to the already linked question suggests a function

def scalify(l):
    return l if len(l) > 1 else l[0]

which will return the list given to it, unless the list has a single element in which case it returns the element. Just what you need want.

Example:

import numpy as np

def scalify(l):
    return l if len(l) > 1 else l[0]

def getitems(inventory,itemtype):
    return inventory[inventory==itemtype]

Inventory   = np.array(['Eggs', 'Milk', 'Ham', 'Eggs'])
Drinks      = 'Milk'
Food        = 'Eggs'

print('The shop has %s' % scalify(getitems(Inventory,Drinks)))

print('The shop has %s' % scalify(getitems(Inventory,Food)))

Output:

The shop has Milk
The shop has ['Eggs' 'Eggs']

For future reference:

As of numpy v1.16, asscalar is deprecated. Use np.ndarray.item instead. As the other answer said, generally it's nicer for functions to only return a single type, but there are notable APIs where this is not the case (like __getitem__ for numpy arrays and even lists!). So I would recommend

from typing import Union, Any

import numpy as np


def maybe_single_item(array: np.ndarray) -> Union[np.ndarray, Any]:
    try:
        return array.item()
    except TypeError:
        return array

(python 3.5+)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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