Porównywanie elementów tej samej tablicy

0

Cześć, chcę napisać skrypt liczący ilość elementów w najdłuższym łańcuchu występujących po sobie wzrostów i spadków wartości liczb w tablicy.
Chodzi mi o coś takiego:

A = [1, 1, 4, 2, 5, -1, 6, 6, 7]
B = [3, 6, 9, 11]

a) mamy ciąg: stałe (1-1), rośnie (1-4), spada (4-2), rośnie (2-5), spada (5, -1), rośnie (-1, 6), stałe (6-6), rośnie (6, 7) => odpowiedź to 6 elementów w łańcuchu (1-4-2-5-(-1)-6)
b) rośnie (3-6), rośnie (6,9), rośnie (9-11) => odpowiedź to 2 elementy (w każdym miejscu tablicy taka odpowiedź bo nie ma spadków)

Próbowałem w ten sposób:

signs = ""
for x, y in zip(A, A[1:]):
    if x >= y:
        signs += '0'
    else:
        signs += '1'

żeby dostać ciąg 0 (spadek) i 1 (wzrost) ale nie wiem co dalej. Proszę o pomoc

0

Nie jestem pewien o co ci konkretnie chodzi, chcesz po prostu wyłapać czy tendencja ma wartości spadkowe czy wzrostowe?
Jeśli tak, to wystarczy zrobić w ten sposób:

def trend(data):
    data_trend = {}
    for idx in range(1, len(data)):
        if data[idx-1] < data[idx]:
			data_trend["up"] = data_trend.get("up", 0)+1
        elif data[idx-1] > data[idx]:
			data_trend["down"] = data_trend.get("down", 0)+1
        else:
			data_trend["equal"] = data_trend.get("equal", 0)+1
	return data_trend
	#~ If you want most common trend:
	#~ return max(data_trend, key=data_trend.get)

a = [1, 1, 4, 2, 5, -1, 6, 6, 7]
b = [3, 6, 9, 11]
print(trend(a)) ## {'equal': 2, 'down': 2, 'up': 4}
print(trend(b)) ## {'up': 3}

#~ Most common option
print(trend(a)) ## up
print(trend(b)) ## up

Chyba że źle zrozumiałem twój problem, to mnie popraw :)

(Opcjonalnie z tego słownika można też wyjąć inne własności, chyba że potrzebujesz czegoś uzależnionego od kolejności, jak na przykład kolejne elementy wzrostowe/spadkowe następujące po sobie nie przerwane przez inne czynności.)

0

Chodzi mu o to (też na to patrzyłem, wysmażyłem nawet coś, ale nie działało, a nie mam czasu teraz debugować for fun:)), żeby znaleźć ilość elementów w najdłuższym ciągu: up, down, up, down..., albo down, up, down, up, ... Czyli dla Twoich a i b, powinno, odpowiednio, zwrócić: 6 (1, 4, 2, 5, -1, 6), 2 (3, 6, albo 6, 9, albo 9, 11).

0
lion137 napisał(a):

Chodzi mu o to (też na to patrzyłem, wysmażyłem nawet coś, ale nie działało, a nie mam czasu teraz debugować for fun:)), żeby znaleźć ilość elementów w najdłuższym ciągu: up, down, up, down..., albo down, up, down, up, ... Czyli dla Twoich a i b, powinno, odpowiednio, zwrócić: 6 (1, 4, 2, 5, -1, 6), 2 (3, 6, albo 6, 9, albo 9, 11).

Dokładnie tak. Najdłuższa taka seria w danej tablicy

2

To w sumie z drobną modyfikacją mam gotowy program do tego :)

def trend_length(data):
    def sign(first, secound):
        if first > secound:
            return -1
        return first < secound
            
    length = 0
    pretendent = 0
    difference = 0
    last = 0
        
    for idx in range(1, len(data)):
        #~ Find difference
        difference = sign(data[idx-1], data[idx])
        
        #~ Check this trend
        if last != difference and not (0 in (last, difference)): #~ If both are 1, and are different
            pretendent += 1
        else: #~ One is 0 or both equal
            if length < pretendent:
                length = pretendent
            if difference:
                pretendent = 2
                
        #~ Save last difference
        last = difference
    
    if length < pretendent: #~ When last trend is the longest
        length = pretendent
    #~ Return result after working loop
    return length 

a = [1, 1, 4, 2, 5, -1, 6, 6, 7]
b = [3, 6, 9, 11]

print(trend_length(a)) ## 6
print(trend_length(b)) ## 2

Jeśli potrzebujesz jeszcze wypisanych tych ciągów, popracuj nad częścią Check this trend :)

Będziesz potrzebować dwóch list do jednej będziesz dodawać elementy gdy pretendent rośnie, druga będzie zastępowana rosnącą gdy length jest zastępowany.

Nie sądzę że jest to zoptymalizowane, ale działa jak powinno :)

0

Jeśli potrzebujesz jeszcze wypisanych tych ciągów, popracuj nad częścią Check this trend :)

Będziesz potrzebować dwóch list do jednej będziesz dodawać elementy gdy pretendent rośnie, druga będzie zastępowana rosnącą gdy length jest zastępowany.

Nie sądzę że jest to zoptymalizowane, ale działa jak powinno :)

Dziękuję bardzo! Działa :D Chciałem tylko zobaczyć jak takie zadanie trzeba rozwiązać. Najlepsze jest to, że dostałem je jako jedno z zadań na rozmowie kwalifikacyjnej na juniora we front-endzie. Próbowałem go robić w taki sposób, że program sprawdzał osobno liczbę powtórzeń up-down i down-up a to co otrzymałem próbowałem jakoś zliczać. Ale program nie działał we wszystkich przypadkach.

1

Nie sądzę że jest to zoptymalizowane, ale działa jak powinno :)

Twoje rozwiązanie to optymalne O(n) time i O(1) space.

Proponuję kilka zmian:

--- trend_length.py
+++ trend_length_fast.py
@@ -1,18 +1,17 @@
-def trend_length(data):
-    def sign(first, secound):
-        if first > secound:
-            return -1
-        return first < secound
+import itertools
 
+def trend_length(data):
     length = 0
     pretendent = 0
     difference = 0
     last = 0
 
-    for idx in range(1, len(data)):
-        difference = sign(data[idx-1], data[idx])
+    a, b = itertools.tee(data)
+    next(b, None)
+    for x, y in zip(a, b):
+        difference = -1 if y < x else 1 if y > x else 0
 
-        if last != difference and not (0 in (last, difference)):
+        if last != difference and last != 0 and difference != 0:
             pretendent += 1
         else:
             if length < pretendent:
>>> from random import randint, seed

>>> seed(42)

>>> xs = [randint(1, 10) for _ in range(1000)]

>>> trend_length(xs) == trend_length_fast(xs)
True

>>> %timeit trend_length(xs)
499 µs ± 4.64 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

>>> %timeit trend_length_fast(xs)
235 µs ± 1.15 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

>>> 

1 użytkowników online, w tym zalogowanych: 0, gości: 1