Wyszukanie tej samej liczby (ID) w drugiej liście, i wyplucie jej pozycji z drugiej listy

0

Definiuje dwie tablice:

        drivers = [[], [], []]
        data = [[], [], [], []]

następnie wypełniam je danymi:

        for i in range(len(driver_name)):
            drivers[0].append(driver_id[i])
            drivers[1].append(driver_name[i].text)
            drivers[2].append(driver_module[i].text)

        for i in range(len(limit_value_text)):
            data[0].append(limit_value_text[i].text)
            data[1].append(name[i].text)
            data[2].append(symbolic_address[i].text)
            data[3].append(driver_id[i])

w końcowym etapie, dane przygotowuje aby zapisać w formacie Excel:

        for i in range(len(data[0])):
            try:
                sheet.cell(row=1, column=2).value = "Limit value text"
                sheet.cell(row=i + 2, column=2).value = data[0][i]

                sheet.cell(row=1, column=3).value = "Name"
                sheet.cell(row=i + 2, column=3).value = data[1][i]

                sheet.cell(row=1, column=4).value = "Symbolic Address"
                sheet.cell(row=i + 2, column=4).value = data[2][i]

                sheet.cell(row=1, column=5).value = "Driver ID"
                sheet.cell(row=i + 2, column=5).value = data[3][i]
            except:
                print("Error")

W ostatnim wierszu, gdzie zapisuje Driver ID sheet.cell(row=i + 2, column=5).value = data[3][i], zamiast ID chciałbym mieć nazwę.
Czyli np, jeśli: data[3][1] == drivers[0][3], to wtedy: sheet.cell(row=i + 2, column=5).value = drivers[1][3]

Jak to najlepiej zrealizować ?

4

o_O

  1. Zrobić klasę Driver która przechowuje te wszystkie dane
  2. Mieć jedną listę obiektów Driver
  3. Profit!
class Driver(object):
    def __init__(self, driver_name, module, limit_value_text, name, symbolic_address):
        self.id = id
        self.driver_name = driver_name
        self.module = module
        self.limit_value_text = limit_value_text
        self.name = name
        self.symbolic_address = symbolic_address

Nagle bierzesz drivers[i] i masz wszystkie dane pod ręką.
Jeśli te dane przychodzą do ciebie w takiej dziwnej formie, to możesz zamiast listy mieć mapę:

drivers = {}
drivers[ID] = Driver(...)

I potem możesz wybrać drivera z tej mapy na podstawie ID i dodać mu te dane do obiektu.

edit: Coś takiego:

class DriverData(object):
    def __init__(self, limit_value_text, name, symbolic_address):
        self.limit_value_text = limit_value_text
        self.name = name
        self.symbolic_address = symbolic_address


class Driver(object):
    def __init__(self, driver_id, driver_name, module):
        self.driver_id = driver_id
        self.driver_name = driver_name
        self.module = module
        self.data = None

    def add_data(self, data):
        self.data = data


drivers = {}
for i in range(len(driver_name)):
    drivers[driver_id[i]] = Driver(driver_id[i], driver_name[i].text, driver_module[i].text)

for i in range(len(limit_value_text)):
    driver = drivers[driver_id[i]]
    driver.add_data(DriverData(limit_value_text[i].text, name[i].text, symbolic_address[i].text))

I voila, zamiast robić jakieś cyrki z indeksami w N-tablicach, masz jedną z kompletnymi obiektami.

0

Bardzo dziękuje za ten przykład i rozwiązanie. Zapoznam się i chętnie to przetestuje.
Ale na szybko zrobiłem coś takiego:

        for i in range(len(limit_value_text)):
            data[0].append(limit_value_text[i].text)
            data[1].append(name[i].text)
            data[2].append(symbolic_address[i].text)
            data[3].append(variables_driver_id[i])
            for k in range(len(variables_driver_id)):
                for g in range(len(driver_id)):
                    if variables_driver_id[k] == driver_id[g]:
                        data[4].append(driver_name[g].text)
                        data[5].append(driver_module[g].text)

i wydaje się że działa. Ale pewnie dużo wolniej niż zaproponowane przez Ciebie rozwiązanie.

0

@Caporeira jakieś milion razy ;) Robisz tam liniowe szukanie, czyli im dłuższa lista tym gorzej. Mogłeś juz użyć tego dicta {} to byłoby przynajmniej szybko, chociaż nadal nieczytelnie. Zauważ że teraz w twoim kodzie musisz pamiętać co masz pod indeksem [3] a co pod [5]. A jak byłoby ich więcej? Zastanów się czy wygodniej napisać drivers[i].driver_name czy data[4][i] i które z nich jest bardziej czytelne?

0

@Shalom:

Zabieram się za ten kod który powyżej napisałeś.
Robię to tak że zbieram dane z 3 plików. Zatem robię 3 listy w których mam po 2/3 informacje.
Następnie, przeszukuje linijkowo wspólnych cech (około 3 tyś linijek). Przy tylu danych trwa to o wiele za długo.

Która linijka w Twoim kodzie odpowiada za przypisanie cech wspólnych ?
Szukając tutorial aby lepiej zrozumieć ten kod i się dokształcić, jakich haseł, zagadnień szukać ?

1

Nie rozumiem o co pytasz. Używam tam dicta po prostu. To jest takie coś co działa jak tablica, tylko ze kluczem moze być cokolwiek, a nie tylko indeks w tablicy.

mapa = {}
mapa['ala'] = 'ala ma kota'
mapa['sierotka'] = 'sierotka ma rysia'

I teraz nie trzeba liniowo szukać sobie Ali, wystarczy napisać mapa['ala'] i dostajesz to co chciałeś w czasie O(1)

0
Shalom napisał(a):

edit: Coś takiego:

class DriverData(object):
    def __init__(self, limit_value_text, name, symbolic_address):
        self.limit_value_text = limit_value_text
        self.name = name
        self.symbolic_address = symbolic_address


class Driver(object):
    def __init__(self, driver_id, driver_name, module):
        self.driver_id = driver_id
        self.driver_name = driver_name
        self.module = module
        self.data = None

    def add_data(self, data):
        self.data = data


drivers = {}
for i in range(len(driver_name)):
    drivers[driver_id[i]] = Driver(driver_id[i], driver_name[i].text, driver_module[i].text)

for i in range(len(limit_value_text)):
    driver = drivers[driver_id[i]]
    driver.add_data(DriverData(limit_value_text[i].text, name[i].text, symbolic_address[i].text))

I voila, zamiast robić jakieś cyrki z indeksami w N-tablicach, masz jedną z kompletnymi obiektami.

Testowałem przed chwilą ten kod. W drugiej pętli jest problem, gdyż:

len(driver_name) = 4
len(limit_value_text) = 2650

Wie druga pętla osiąga limit przy 4 pętli.

Chodzi o to że jeden plik zawiera te dane:

limit_value_text[i].text, name[i].text, symbolic_address[i].text, **variables_driver_id[i]**

drugi zawiera:

**driver_id[g]** , driver_name[g].text, driver_module[g].text

Przy czym variables_driver_id[k] == driver_id[g] to jest wspólna cecha tych dwóch list/słowników.

Jako że klucze muszą być unikatowe, więc kluczem musi być jedna z tych wartości: name[i].text lub symbolic_address[i].text

W kolejnym etapie dochodzić będzie trzecia tablica, której cechą wspólną będzie limit_value_text[i].text

1

Nie rozumiem o co ci chodzi. Nie pokazałes żadnych danych, a ja napisałem kod z palca który mniej więcej powinien działać. Czego oczekujesz? Że mam szklaną kulę? o_O Pokaż dokładnie co chcesz zrobić bo inaczej się nie dogadamy. Albo w ogóle zostaw to i zleć komuś kto umie programować, bo sam sobie ewidentnie nie radzisz.
Przecież te o pętle wziąłem od ciebie, sam miałeś tam for i in range(len(driver_name)): więc nie rozumiem gdzie widzisz problem.

0

@Shalom: Nie chciałem Cię zdenerwować, a jeśli tak się stało .. to przepraszam.
Nie jestem doświadczonym programistą, ale staram się samemu czegoś małymi krokami nauczyć.
Wolałbym to samemu zrobić, bo to większa frajda samemu zrobić (przy czyjejś pomocy).

Masz rację że lepiej mieć opisane te klucze, więc zacząłem tak to robić:


d3 = {}
d4 = {}
for k in range(len(limit_value_text)):
                d3[k] = {'name': name[k].text, 'limit_value_text':limit_value_text[k].text, 'symbolic_address': symbolic_address[k].text, 'variables_driver_id':variables_driver_id[k]}

for m in range(len(driver_id)):
                d4[m] = {'driver_id': driver_id[m], 'driver_name': driver_name[m].text, 'driver_module': driver_module[m].text}

for key, value in d3.items():
            print(value['variables_driver_id'])

I teraz chce wykonać, jeśli :

d3(variables_driver_id) == d4(driver_id)

dodaj do d3 dodać z d4

('driver_id': driver_id, 'driver_name':driver_name.text, 'driver_module':driver_module.text)

Czyli połączyć słowniki dopasowując po tych samych id.
Jak to najlepiej zrobić ?

d3 ma 2460 głównych kluczy
d4 ma ich 4

0

Masz rację że lepiej mieć opisane te klucze, więc zacząłem tak to robić:

To co napisałeś nie ma najmniejszego sensu. PO CO nadal trzymasz to w jakichś tablicach indeksowanych intami? Czemu nie zrobisz tam klucza variables_driver_id[k] zamiast k? o_O

d3[variables_driver_id[k]] = {'name': name[k].text, 'limit_value_text':limit_value_text[k].text, 'symbolic_address': symbolic_address[k].text}

i analogicznie

d4[driver_id[m]] = {'driver_name': driver_name[m].text, 'driver_module': driver_module[m].text}

i voila, nagle możesz zrobić d3[id] oraz d4[id].

To samo zreszta sugerowałem 1.5 miesiaca temu...

0

@Shalom:
Chodzi o to że w pierwszym etapie porównuje ID
A w drugim będę chciał porównać limit_value_text z innym plikiem.

Czyli z 3 plików chce stworzyć jeden słownik.

0

Obawiam się że się nie dogadamy, bo to co mówisz w ogóle się nie kompiluje w logiczną całość. Pokaż te swoje dane albo ich kawałek, bo inaczej to jeszcze pół roku będziesz nad tym siedzieć.

0

@Shalom
czy ten kod był zamierzony?

drivers = {}
for i in range(len(driver_name)):
    drivers[driver_id[i]] = Driver(driver_id[i], driver_name[i].text, driver_module[i].text)

Stąd wynikło pytanie @Caporeira :

Testowałem przed chwilą ten kod. W drugiej pętli jest problem, gdyż:

len(driver_name) = 4
len(limit_value_text) = 2650
Wie druga pętla osiąga limit przy 4 pętli.

Tak czy siak łopatologicznie to parsujesz 3 pliki odpowiednio do obiektów i zapisujesz do dicta na podstawie jakieś wspólnej wartości pomiędzy dictami. Z tego co piszesz między listą 1 a 2 wspólne wartości to:

variables_driver_id[k] == driver_id[g]

Ale nie są niestety unikalne. Dlatego można zrobić taki myk:

...parsujesz plik, znajdujesz driver z id = 10...
if id not in drivers:
    drivers[id] = []
driver[id].append(Driver(id, inne argumenty sparsowane z pliku))
(mozna to tez defaultdict rozwiazac, ale juz nie mieszam w kodzie)

Przykładowo dla pliku 1 o wartosciach:

id=10,costam1
id=14,costam2
id=10,costam3
id=234,costam4

Stworzy nam dicta:

file1_dict = { '10': [Driver(costam1), Driver(costam3)], '14': [Driver(costam2)], '234':  [Driver()]'}

Dzięki temu rozwiązaniu jak będziesz parsował drugi plik, który również posiada id ale może nie posiadać takich samych argumentów możesz stworzyć kod w stylu:

.. sparsuj plik2 ...
for id in plik2:
    if id in file1_dict: 
        for driver in file1_dict[id]:
            # zaktualizuj wartosci na podstawie pliku2
    else:
       file1_dict[id] = []
       # dodaj nowy driver jak w plik1

W razie gdyby id były wspólne oraz unikalne byłoby to jeszcze łatwiejsze bo można pozbyć się listy driverów dla każdego id.
Dla pliku 3 dla którego wspólna cechą jest limit_value możesz po prostu zmapować plik3 na limit_value i potem przeiterować drivers (stworzone z pliku 1 i 2) i zaktualizować wartości jeżeli dany driver ma limit_value jak z pliku 3.

0

I teraz realny przykład, najlepiej operować na małych sztucznych przykładach jak tworzysz rozwiązania bo łatwiej zrozumieć algorytmy.

Plik1:

# id,name,address
10,ABC,453
45,HYU,893
432,NVC,84
10,FGT,50

Plik2:

#id,limit_value_text
10,100
45,45
432,100

Plik3:

#limit_value_text,custom_field
100,A
45,B
500,C
class Driver:
   def __init__(self, id, name, address):
        self.id = id
        self.name = name
        self.address = address
drivers = {}
with open('plik1.txt') as f:
   for line in f:
      id, name, address = line.split(',', maxsplit=3)
      if id not in drivers:
          drivers[id] = []
     drivers[id].append(Driver(id, name, address)
with open('plik2.txt') as f:
   for line in f:
     id, limit_value_text = line.split(',', maxsplit=2)
     if id in drivers:
         for index, driver in drivers[id]:
             driver.limit_value_text = limit_value_text
             drivers[id][index] = driver
with open('plik3.txt') as f:
    for line in f:
       limit_value_text, custom_field = line.split(',', maxsplit=2)
     if id in drivers:
         for index, driver in drivers[id]:
             if driver.limit_value_text == limit_value_text:
                 driver.custom_field = custom_field
                 drivers[id][index] = driver

(Mogłem zrobić błędy w kodzie, kod może być napisany lepiej)
drivers na końcu powinno wyglądać tak:

{
'10': [Driver(id=10, name=ABC,address=453, limit_value_text=100, custom_field=A), Driver(id=10, name=FGT,address=50, limit_value_text=100, custom_field=A)],
'45': [Driver(id=45, name=HYU,address=893, limit_value_text=45, custom_field=B)],
'432':[Driver(id=432, name=NVC,address=84, limit_value_text=100, custom_field=A)]]
}

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