Hoe kan ik een lijstvorm krijgen zonder numpy te gebruiken?

Als np.shapewordt gebruikt, geeft lijst a1(6,)terug en b1geeft (2, 3).

Als Numpy verboden is, hoe krijg ik dan de vorm van lijst a1?

Ik ben vooral in de war over hoe ik het python-programma kan laten weten dat a1slechts één dimensie is. Is er een goede methode?


Antwoord 1, autoriteit 100%

>>>a = [1,2,3,4,5,6]
>>>print (len(a))
6

Voor eendimensionale lijsten kan de bovenstaande methode worden gebruikt. len(list_name) geeft het aantal elementen in de lijst terug.

>>>a = [[1,2,3],[4,5,6]]
>>>nrow = len(a)
>>>ncol = len(a[0])
>>>nrow
2
>>>ncol
3

Het bovenstaande geeft de dimensie van de lijst. len(a) geeft het aantal rijen terug. len(a[0]) geeft het aantal rijen in a[0] terug, wat het aantal kolommen is.

Hier is een linknaar het oorspronkelijke antwoord.


Antwoord 2, autoriteit 29%

dit is een recursieve poging om uw probleem op te lossen. het werkt alleen als alle lijsten op dezelfde diepte even lang zijn. anders zal het een ValueErroropleveren:

from collections.abc import Sequence
def get_shape(lst, shape=()):
    """
    returns the shape of nested lists similarly to numpy's shape.
    :param lst: the nested list
    :param shape: the shape up to the current recursion depth
    :return: the shape including the current depth
            (finally this will be the full depth)
    """
    if not isinstance(lst, Sequence):
        # base case
        return shape
    # peek ahead and assure all lists in the next depth
    # have the same length
    if isinstance(lst[0], Sequence):
        l = len(lst[0])
        if not all(len(item) == l for item in lst):
            msg = 'not all lists have the same length'
            raise ValueError(msg)
    shape += (len(lst), )
    # recurse
    shape = get_shape(lst[0], shape)
    return shape

gezien uw input (en de input van de opmerkingen) zijn dit de resultaten:

a1=[1,2,3,4,5,6]
b1=[[1,2,3],[4,5,6]]
print(get_shape(a1))  # (6,)
print(get_shape(b1))  # (2, 3)
print(get_shape([[0,1], [2,3,4]]))  # raises ValueError
print(get_shape([[[1,2],[3,4]],[[5,6],[7,8]]]))  # (2, 2, 2)

niet zeker of het laatste resultaat is wat je wilde.


UPDATE

zoals aangegeven in de opmerkingen van mklzal de bovenstaande code niet alle gevallen opvangen waarin de vorm van de geneste lijst is inconsistent; bijv. [[0, 1], [2, [3, 4]]]geeft geen foutmelding.

dit is een poging om te controleren of de vorm consistent is (misschien is er een efficiëntere manier om dit te doen…)

from collections.abc import Sequence, Iterator
from itertools import tee, chain
def is_shape_consistent(lst: Iterator):
    """
    check if all the elements of a nested list have the same
    shape.
    first check the 'top level' of the given lst, then flatten
    it by one level and recursively check that.
    :param lst:
    :return:
    """
    lst0, lst1 = tee(lst, 2)
    try:
        item0 = next(lst0)
    except StopIteration:
        return True
    is_seq = isinstance(item0, Sequence)
    if not all(is_seq == isinstance(item, Sequence) for item in lst0):
        return False
    if not is_seq:
        return True
    return is_shape_consistent(chain(*lst1))

die op deze manier kunnen worden gebruikt:

lst0 = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
lst1 = [[0, 1, 2], [3, [4, 5]], [7, [8, 9]]]
assert is_shape_consistent(iter(lst0))
assert not is_shape_consistent(iter(lst1))

Antwoord 3, autoriteit 10%

Hier is een goed voorbeeld uit het boek “Ten Essays on Fizz Buzz”van Joel Grus met behulp van recursie.

from typing import List, Tuple, Union
def shape(ndarray: Union[List, float]) -> Tuple[int, ...]:
    if isinstance(ndarray, list):
        # More dimensions, so make a recursive call
        outermost_size = len(ndarray)
        row_shape = shape(ndarray[0])
        return (outermost_size, *row_shape)
    else:
        # No more dimensions, so we're done
        return ()

Voorbeeld:

three_d = [
    [[0, 0, 0], [1, 1, 1], [2, 2, 2]],
    [[0, 0, 0], [1, 1, 1], [2, 2, 2]],
    [[0, 0, 0], [1, 1, 1], [2, 2, 2]],
    [[0, 0, 0], [1, 1, 1], [2, 2, 2]],
    [[0, 0, 0], [1, 1, 1], [2, 2, 2]],
]
result = shape(three_d)
print(result)
>>> (5, 3, 3)

Antwoord 4, autoriteit 10%

In de vraag staat duidelijk ‘zonder numpy te gebruiken’. Als iemand hier echter is op zoek naar een oplossing zonder enige voorwaarde, overweeg dan hieronder. Deze oplossing werkt voor een evenwichtige lijst.

b1=[[1,2,3], [4,5,6]]
np.asarray(b1).shape

(2, 3)


Antwoord 5, Autoriteit 5%

Afhankelijk van het vereiste niveau van grondstoffen, zou ik aanraden om de staartrecursie te gebruiken. Bouw de vorm op uit de binnenste naar de buitenste lijst. Hiermee kunt u controleren of alle maten overeenkomen met elke diepte en index.

def shape(lst):
    def ishape(lst):
        shapes = [ishape(x) if isinstance(x, list) else [] for x in lst]
        shape = shapes[0]
        if shapes.count(shape) != len(shapes):
            raise ValueError('Ragged list')
        shape.append(len(lst))
        return shape
    return tuple(reversed(ishape(lst)))

Hier is een demo op ideone: https://ideo.com/hjrwlc

shapes.count(shape) != len(shapes)is een nette truc om te bepalen of alle vormen tot een bepaald niveau identiek zijn, genomen van https://stackoverflow.com/a/3844948/2988730 .

Als uw enige doel is om te bepalen of de lijst één dimensionaal is of niet, voert u gewoon een enkele allop de buitenste lijst:

is_1d = all(not isinstance(x, list) for x in lst)

of

is_1d = not any(isinstance(x, list) for x in lst)

Antwoord 6

De volgende functie houdt het eerste item van elke dimensie van een lijst bij. Het maakt niet uit hoeveel dimensies het heeft.

def list_shape(input):
shape = []
    a = len(input)
    shape.append(a)
    b = input[0]
    while a > 0:
        try:
            a = len(b)
            shape.append(a)
            b = b[0]
        except:
            break
    return shape
list1 = [[[123], [231]], [[345], [231]]]
print(list_shape(list1))

Uitvoer:

[2, 2, 1]

Opmerking: werkt alleen voor symmetrische lijsten en numerieke gegevens binnen de lijst.

Other episodes