Czy istnieje wygodny jednowierszowy program do generowania listy liczb i ich ujemnych odpowiedników w Pythonie?
Powiedzmy na przykład, że chcę wygenerować listę o numerach od 6 do 9 i od -6 do -9.
Moje obecne podejście to:
l = [x for x in range(6,10)]
l += [-x for x in l]
Prostym „jednowierszowym” byłoby:
l = [x for x in range(6,10)] + [y for y in range(-9, -5)]
Jednak generowanie dwóch list, a następnie łączenie ich ze sobą wydaje się niewygodne.
python
python-3.x
upe
źródło
źródło
scalar or array-like, shape
byłby w porządku.Odpowiedzi:
Nie jestem pewien, czy kolejność ma znaczenie, ale możesz utworzyć krotkę i rozpakować ją w liście.
źródło
Utwórz miłą i czytelną funkcję:
Stosowanie:
W ten sposób otrzymujesz wygodną jednowarstwową na wszystko. Unikaj próby wyglądania jak magiczny haker pro.
źródło
y
nasignedValue
. Dla mnie prawdziwą wartością dodaną podejścia „definiuj funkcję” byłoby dostarczanie wyników w ścisłej kolejności zadawanego pytania (pozytywna, a następnie negatywna), przy jednoczesnym unikaniu problemu jednowierszowego Barmara,chain
w którym nieco inne argumenty liczbowe mają zostać zakodowanym dwukrotnie.list
czegokolwiek.) Po latach prób kodyfikowania najlepszego sposobu podejmowania tych decyzji, jedyna ogólna zasada, która ma dla mnie sens : jeśli w programie jest coś oczywistego, dobrego imienia, skorzystaj z okazji (a funkcje to jeden ze sposobów, w jaki to robimy).Powiedziałbym, że najprostszym rozwiązaniem jest rozpakowanie dwóch zakresów na listę za pomocą
*
operatora rozpakowywania:Jest to nie tylko najkrótsza jak dotąd zaproponowana odpowiedź, ale także najbardziej wydajna, ponieważ tworzy ona tylko jedną listę i nie wymaga żadnych wywołań funkcji poza tymi dwoma
range
.Zweryfikowałem to, testując wszystkie odpowiedzi na to pytanie za pomocą
timeit
modułu:(testy czasu przeprowadzane za pomocą Pythona 3.6.9 na moim komputerze (średnie specyfikacje))
źródło
[*range(x, y), *range(-y + 1, -x + 1)]
Możesz użyć
itertools.chain()
do połączenia dwóch zakresów.źródło
Możesz użyć
itertools.product
, który jest produktem kartezjańskim.Może to być wolniejsze, ponieważ używasz mnożenia, ale powinno być łatwe do odczytania.
Jeśli potrzebujesz czysto funkcjonalnego rozwiązania, możesz również zaimportować
itertools.starmap
ioperator.mul
:Jest to jednak mniej czytelne.
źródło
product
,starmap
iopertaor.mul
niepotrzebnie rozwarty porównaniu do zagnieżdżonych listowych, ale ja popieram sugestię używając mnożenia.[x * sign for sign in (1, -1) for x in range(6, 10)]
jest tylko 10% wolniejszy niż[y for x in range(6, 10) for y in (x, -x)]
, aw przypadkach, gdy liczy się kolejność, ponad 3 razy szybszy niż sortowanie podejścia opartego na krotkach.starmap
imul
należy go unikać, ale myślę, żeproduct
czyni go bardziej czytelnym, ponieważ grupuje iteratory i ich elementy osobno. Podwójne pętle w rozumieniu listy mogą być również mylące ze względu na ich nieoczekiwaną kolejność.Jesteś naprawdę blisko dzięki połączeniu dwóch
range
obiektów. Ale jest na to łatwiejszy sposób:Oznacza to, że przekonwertuj każdy
range
obiekt na listę, a następnie połącz dwie listy.Inne podejście przy użyciu itertools:
itertools.chain()
jest jak uogólniony+
: zamiast dodawać dwie listy, łączy jeden iterator po drugim, tworząc „super-iterator”. Następnie przekaż to do,list()
a otrzymasz konkretną listę ze wszystkimi liczbami, które chcesz w pamięci.źródło
[x for x in ...]
lepszą pisownięlist(...)
.Ważenie z jeszcze jedną możliwością.
Jeśli chcesz czytelności, twój oryginalny linijka była całkiem dobra, ale zmieniłbym zakresy, aby były takie same, ponieważ uważam, że ujemne granice sprawiają, że wszystko jest mniej wyraźne.
źródło
IMO podejście wykorzystujące
itertools.chain
przedstawione w kilku innych odpowiedziach jest zdecydowanie najczystsze z podanych do tej pory.Ponieważ jednak w twoim przypadku kolejność wartości nie ma znaczenia , możesz uniknąć konieczności definiowania dwóch jawnych
range
obiektów, a tym samym unikania wykonywania wszystkich obliczeń matematycznych potrzebnych dorange
indeksowania ujemnego , używającitertools.chain.from_iterable
:Tad gadatliwy, ale wystarczająco czytelny.
Inną podobną opcją jest użycie rozpakowywania krotek / argumentów za pomocą zwykłego
chain
:Bardziej zwięzłe, ale uważam, że rozpakowywanie krotki jest trudniejsze w szybkim skanowaniu.
źródło
Jest to wariacja na temat (patrz @Derte trdelník „s odpowiedź ) po filozofię
itertools
, gdzieChodzi o to, że podczas definiowania nowej funkcji równie dobrze możemy uczynić ją ogólną:
i zastosuj do konkretnego
range
iteratora:źródło
Jeśli chcesz zachować ustaloną kolejność, możesz skorzystać z wbudowanego generatora zasięgu Pythona z warunkiem:
Co daje wynik:
Działa również z 0 jako początkiem pełnego zakresu.
źródło
start
.Istnieją różne sposoby wykonania pracy.
Podane zmienne: 1. start = 6 2. stop = 10
Możesz spróbować również w przypadku innego podejścia:
źródło
Po prostu lubię symetrie.
a = 6 b = 10
nums = [x + y dla x w (- (a + b-1), 0) dla y w zakresie (a, b)]
Wynik powinien wynosić -9, -8, ..., 8, 9.
Uważam, że można poprawić ekspresję nums, co po „in” i „range” nadal wydaje mi się niezrównoważone.
źródło