Getting Only Element from a Single-Element List in Python

Getting only element from a single-element list in Python?

Raises exception if not exactly one item:

Sequence unpacking:

singleitem, = mylist
# Identical in behavior (byte code produced is the same),
# but arguably more readable since a lone trailing comma could be missed:
[singleitem] = mylist

Rampant insanity, unpack the input to the identity lambda function:

# The only even semi-reasonable way to retrieve a single item and raise an exception on
# failure for too many, not just too few, elements as an expression, rather than a
# statement, without resorting to defining/importing functions elsewhere to do the work
singleitem = (lambda x: x)(*mylist)

All others silently ignore spec violation, producing first or last item:

Explicit use of iterator protocol:

singleitem = next(iter(mylist))

Destructive pop:

singleitem = mylist.pop()

Negative index:

singleitem = mylist[-1]

Set via single iteration for (because the loop variable remains available with its last value when a loop terminates):

for singleitem in mylist: break

There are many others (combining or varying bits of the above, or otherwise relying on implicit iteration), but you get the idea.

Pythonic way to get the single element of a 1-sized list

This blog post suggests an elegant solution I fell in love with:

(item,) = singlet_list

I find it much more readable, and plus it works with any iterable, even if it is not indexable.

EDIT: Let me dig a little more

This construct is called sequence unpacking or multiple assignment throughout the python documentation, but here I'm using a 1-sized tuple on the left of the assignment.

This has actually a behaviour that is similar to the 2-lines in the initial question: if the list/iterable singlet_list is of length 1, it will assign its only element to item. Otherways, it will fail with an appropriate ValueError (rather than an AssertionError as in the question's 2-liner):

>>> (item,) = [1]
>>> item
1
>>> (item,) = [1, 2]
ValueError: too many values to unpack
>>> (item,) = []
ValueError: need more than 0 values to unpack

As pointed out in the blog post, this has some advantages:

  • This will not to fail silently, as required by the original question.
  • It is much more readable than the [0] indexing, and it doesn't pass unobserved even in complex statements.
  • It works for any iterable object.
  • (Of course) it uses only one line, with respect to explicitly using assert

How to extract the member from single-member set in python?

Tuple unpacking works.

(element,) = myset

(By the way, python-dev has explored but rejected the addition of myset.get() to return an arbitrary element from a set. Discussion here, Guido van Rossum answers 1 and 2.)

My personal favorite for getting an arbitrary element is (when you have an unknown number, but also works if you have just one):

element = next(iter(myset)) ¹

1: in Python 2.5 and before, you have to use iter(myset).next()

Handling lists and one element not list type

There aren't that many functions that behave like that, exactly for the reason you stated. plt.subplots tries to provide a convenience for users creating a single subplot, or a row or column of subplots. This behavior can be turned off easily using the squeeze parameter, in which case axis will become a 2D numpy array.

You can do

f, axis = plt.subplots(N, 1, sharex=True, squeeze=False)
for ax in axis.ravel():
ax.plot(x,y)

The call to ravel ensures that you have a 1D array in all cases.

For a more general solution, you have some options. If the shape of the result depends on the input, you can use an if statement:

if N == 1: axis = [axis]

If the type of return iterable is known up-front, e.g., np.ndarray, you could use isinstance:

if not isinstance(axis, np.ndarray): axis = [axis]

And finally, you could use exception handling:

try:
for ax in axis:
ax.plot(x, y)
except TypeError:
axis.plot(x, y)

This can be rephrased to avoid redundancy:

try:
iter(axis)
except TypeError:
axis = [axis]

All the cases, specific or general, are messy. Having very different types of return values is not a good design for this exact reason. Unfortunately, you have to find some way to compensate if the function doesn't let you turn it off.

Python list comprehension: Unlist if list contains only one element

How about adjusting the way you construct output_names like:

outputs = session.get_outputs()
output_names = [output.name for output in outputs] if len(outputs)>1 else outputs.name

That said, mixing data types is not desirable, imo.

Can I return a single element of a list, as a list?

To answer your question directly, the following will do it:

inventory = [inventory[1]]

This creates a single-element list consisting of the first element of inventory, and assigns it back to inventory. For example:

>>> inventory = ['aaa', 'bbb', 'ccc']
>>> inventory
['aaa', 'bbb', 'ccc']
>>> inventory = [inventory[1]]
>>> inventory
['bbb']

An arguably cleaner way is to use a list comprehension to select elements of inventory that match the given criterion:

>>> inventory = ['aaa', 'bbb', 'ccc']
>>> target = 'bbb'
>>> inventory = [item for item in inventory if (not target) or (item == target)]
>>> inventory
['bbb']


Related Topics



Leave a reply



Submit