Szukam algorytmu - /po podpowiedziach pewnie pojawi sie tu w tytule, nazwa tego algorytmu/

0

Robie pewne operacje na artykulach w jednym ze swoich podwidokow. Artykuly do tego podwidoku przekazuje z okna glownego. Te artykuly charakteryzuja się tym ze maja w sobie liste materialowa /BOM, bill of materials, recepture - okreslenia na to sa rozne/. W takiej liscie skladowej danego artykulu mogą być materialy proste, polwyroby zlozone ale nie moze byc artykulu samego w sobie.

material prosty - material nie dajacy sie juz bardziej podzielic, ktory nie sklada sie juz z zadnego skladu. (np. srubka, nakretka, korpus obudowy, nozka obudowy, gumowa podkladka nozki itp.)
polwyrob zlozony - polwyrob skladajacy sie z polaczonych paru materialow prostych ale tez moze w sobie zawierac inne polwyroby zlozone np.

powyrob 1 - pakiet przygotowanej/zlozonej nozki obudowy sklada sie z:

  • 1szt. nozka obudowy
  • 1szt. gumpowa podkladka
  • 1sz. srubka

polwyrob 2 - pakiet przygotowanej obudowy uniwersalnej gotowej do zamontowania w sobie customizowanego pod klienta wyposazenia sprzetowego

  • 1szt. korpus obudowy
  • 4szt. nakretki
  • 4szt. polwyrob 1 (przygotowane nozki tylko do przykrecenia nakretka w korpusie obudowy

Poziomow zagniezdzania polwyrobow w wyrobie jest pare i dla kazdego polwyrobu jest roznie, jeden ma jeden poziom, inny 5 poziomow nizej. Im artykul zlozony jest wyzej w hierarchi artykulow tym jest bardziej unikatowy/customizowany, im nizej tym bardziej ogolny. Np. roznych wyrobow gotowych do klientow jest kilkaset, ale typow obudow jest juz tylko kilkanascie, a pakiet nozki jest np. tylko jeden.

Szukam algorytmu wzglednie prostego ktory spelni takie oczekiwania.

  1. pobierajac do podwidoku jeden dany artykul, automatycznie chce pobierac kazda jego skladową zlozoną /z tym nie mam problemu po prostu smigam rekurencyjnie wglab receptur i pobieram artykuly zlozone/.
  2. ale jezeli z podwidoku usuwam jeden artykul to chcialbym aby usunac z tego podwidoku rozwniez jegoskladowe zlozone ale tylko takie ktore w tym podwidoku sa czescia tylko tego usuwanego nadrzednego artykulu, nie chce usuwac skladowych ktore sa i w tym usuwanym artykule i sa w innych artykulach juz dodanych do podwidoku.
  3. w podwidoku wszystkie wybrane artykuly wraz z zawartywi w nich skladowymi wyswietlam tylko raz /bez powtorzen/
  4. chce generowac linieimportu dla kazdej unikalnej skladowej tylko raz. (nie chce zawalic bazy liniami importu 100sztukami linii dla kazdego pakietu nozki obudowy )

Będe wdzieczny za jakies hasla klucze, jeszcze lepiej za opis jak to realizowac a jak juz bym dostal kawalek kodu to juz w ogóle.

Jezeli cos niejasno opisalem a ktos "mysli patrzac na interfejsc" to w tym watku ponizej umiescilem fragment tego interfejsu.
Konkretnie to co realizuje to, musze wyliczyc czas wydania z magazynu dla kazdego artykulu zlozonego m.in. w oparciu o ilosc skladowych w liscie skladowej w danym artykule.
Podwidok zapewniac ma zmiane nastaw i wizualizacje wynikow wyliczen na zaznaczonej puli artykulow zlozonych.

Link do grafiki interfejsu

1

Przyznam ze trochę nie rozumiem jakiego "algorytmu" szukasz. Jeśli w ogóle to prędzej jakiejs sensownej struktury danych, ale troche gubię się w tym że ty chcesz pokazywać składowe złożone a nie rozwijać to do materiałów prostych. No bo co się niby dzieje kiedy masz jakiś artykuł który sie składa z X i Y, i masz drugi artykuł który składa się z Z i V, ale V składa się z X i Y? Co się wyświetla w tym twoim podsumowaniu? To co i ile razy będzie u ciebie pokazane? Tylko 1 poziom (czyli X, Y, Z, V) czy może jakoś inaczej?

Nie bardzo rozumiem też gdzie dokładnie jest problem, bo skoro masz aktualne podsumowanie i masz algorytm (rekurencyjny?) który generuje podsumowanie dla konkretnego artykułu, to możesz możesz użyc tego algorytmu a potem usunąć z aktualnego podsumowania to co ci wyszło dla tego usuwanego artykułu?
W praktyce można by w ogóle podejść do tego jak do wzorca Composite to zamiast robić jakieś dziwne rekurencje, niech każdy obiekt potrafi zwrócić swoje "podsumowanie" jako jakieś Map<Identifier, Count> (prosty zwraca jeden element w mapie, samego siebie, a złożony pobiera podsumowania swoich element i "sumuje")

0

Wlasnie się obawiałem ze moge miec problem z przekazaniem o co mi chodzi, na razie zlapalem pomysl na nadmiarowe rozwiazanie swojego problemu, mysle ze za pare dni zaloguje tu przyklady jak to ogarnalem i ewentualnie wtedy poprosze o pomysl na optymalizacje.

W skrocie robie tak ze do przeliczen pobieram wszystko ze wszystkimi powielaniami artykulow zlozonych "dzieci" na calej kolekcji robie w pamieci przelicznia ale na Widoku prezentuje tylko te artykuly niepowtarzajace sie oraz generuje linie importu rowniez tylko dla niepowtarzajacych sie artykulow. Wiec nadmiarowosc mam tylko podczas obliczen w pamieci.

@Shalom - moze z innej strony przedstawie co chce uzyskac. Artykul zlozony oprocz listy materialowej ma rowniez liste operacji jakie trzeba wykonac aby wyprodukowac ten polwyrob/wyrob. Kazda operacja ma zdefiniowany czas nomatywny na jej wykonanie oraz instrukcje co i jak na tym etapie trzeba zrobic. Kazda taka lista operacji zaczyna sie od operaci wydania materialow z magazynu** i to jest glowny cel, to sa operacje do ktorych musze sie dobrac** i w ktorych "hurtowo" musze przeliczyc i wprowadzic zaktualizowany czas do wydania. Bo obecne sa beznadzieje powprowadzane albo kilkadziesiat razy za male albo kilkukrotnie za duze, algorytm wyliczania tych czasow jest tu wewnetrzna sprawa i nie dotyczy pytania ktore zadalem. Artykulow zlozonych w systemie ERP jest kilkanascie tysiecy wiec chce uniknac tego aby dawac to ludziom.

1

A mógłbyś pokazać na tym swoim przykładzie co chcesz osiągnąć? Załóżmy, ze mamy produkt X który składa się z półproduktu 1 i półproduktu 2, jaki miałby być output w takiej sytuacji? Jak wyglądają dla czegoś takiego te twoje linie importu?

0

na tym screenie jest struktura artykulow, oraz przyklady skladow materialowych niektorych artykulow zlozonych:
w skrocie:
jezeli index zaczyna sie wyrazem jednoliterowym to to jest material prosty,
jezeli index zaczyna sie wyraze dwuliterowym, i pierwsza litera tego czlonu jest "Z" to to artykul zlozony (czyli zawierajacy BOM i marszrute)
Przechwytywanie1.PNG

a tu ponizej opisalem krok po kroku jak by to mialo dzialac
Przechwytywanie2.PNG

1

Ale czy ten widok w takim układzie nadal nie jest nadmiarowy? Bo pokazujesz np. zarówno ZK GHI jak i ZO AAA, mimo że jedno z tych ZO AAA jest częścią ZK GHI. Czy jakbym usunął niebieski to ZO AAA ma zniknąć, mimo że w praktyce nadal występuje jako część ZK GHI? Bo jeśli w ogóle nie schodzimy w dół tego ZK GHI do jego elementów składowych tylko patrzymy zawsze na "pierwszy poziom" to nie wiem gdzie tu jest jakis problem.
Nie rozumiem też do końca czemu w widoku pomijasz w ogóle te materiały proste, ale zakładam ze to kwestia "biznesowa".

0

W tym narzędziu materiały proste nie są potrzebne, chodzi o aktualizację czasów wydań w całym drzewie artykułów złożonych zaznaczonego artykułu złożonego.

0

W sumie wypociłem coś co działa.

Wszystko oparlem o liczniki wystapien operacji wydan magazynowych w kolekcji wszystkich operacji pobranych do przekalkulowania.
Jezeli dodam dwa drzewa bardzo podobnych indexow, to elementy zagniezdzone w kazdym z nich ktore sie w obu drzewach powtarzaja beda mialy licznik wystapien = 2.
Dlatego jezeli jeden index usuwam /jedno drzewo/ to tak naprawde usuwam tylko zawarte w nim indexy z licznikiem wystawien = 1, jezeli licznik wystapien jest wiekszy niz jeden to tylko odejmuje wartosc 1 od licznika tego elementu.

Podgląd wyników i kolejne pytania tutaj

Kod ponizej. Konstruktywna krytyka mile widziana.

        private ObservableCollection<KalkulowanaOperacjaWydania> listaKalkulowanychOperacji;
        public ObservableCollection<KalkulowanaOperacjaWydania> ListaKalkulowanychOperacji
        {
            get { return listaKalkulowanychOperacji; }
        }

        private void SynchronizacjaPrzeliczaniaZacheckowanychArtykulow(object sender, NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    ArtykulScalaVM swiezoZacheckowanyArtykul = (ArtykulScalaVM)e.NewItems[0];
                    if (swiezoZacheckowanyArtykul != null)
                        DodajOperacjeWydanDlaIndexu(swiezoZacheckowanyArtykul.Index);                    
                    break;
                case NotifyCollectionChangedAction.Remove:
                    ArtykulScalaVM swiezoOdcheckowanyArtykul = (ArtykulScalaVM)e.OldItems[0];
                    if (swiezoOdcheckowanyArtykul != null)
                        UsunOperacjeWydanDlaIndexu(swiezoOdcheckowanyArtykul.Index);
                    break;
            }
        }
                

        private  void DodajOperacjeWydanDlaIndexu(string index)
        {
            List<KalkulowanaOperacjaWydania> lista = CzysaJuzDodaneOperacjeDlaTegoIndexu(index);

            if (lista!=null && lista.Count != 0)
                foreach (var item in lista)
                    item.LicznikWystapien++;
            else
            {
                IEnumerable<OperacjaTechnologiczna> listaOT = 
                    MarszrutyRepo.PobierzOperacjeWydanDla(index, zakresIndexowOrazOperacji.KolekcjaSzukanychKodStanowisk);
                IEnumerable<ParaIndexNrOperacjiZwiazanej> indexyPodrzedne = 
                    RecepturyRepo.ZwrocParyNrOperacjiIndexPodrzednyDla(index);

                foreach (var item in listaOT)
                {
                    KalkulowanaOperacjaWydania kalkulowanaOpDoDodania = new KalkulowanaOperacjaWydania(
                                item,
                                indexyPodrzedne, 
                                nastawy, 
                                zakresIndexowOrazOperacji);

                    kalkulowanaOpDoDodania.LicznikWystapien++;
                    ListaKalkulowanychOperacji.Add(kalkulowanaOpDoDodania);
                }

                foreach (var item2 in indexyPodrzedne)
                    if (zakresIndexowOrazOperacji.CzyPasujeIndex(item2.Index))
                        DodajOperacjeWydanDlaIndexu(item2.Index);
            }    
            
        }
        private void UsunOperacjeWydanDlaIndexu(string index)
        {
            List<KalkulowanaOperacjaWydania> lista = CzysaJuzDodaneOperacjeDlaTegoIndexu(index);

            if (lista != null && lista.Count != 0)
            {
                foreach (var item in lista)
                {
                    if (item.LicznikWystapien > 1)
                        item.LicznikWystapien--;
                    else
                        listaKalkulowanychOperacji.Remove(item);

                    foreach (var item2 in item.ListaMaterialowWydawanychZTejOperacji)
                        if (zakresIndexowOrazOperacji.CzyPasujeIndex(item2))
                            UsunOperacjeWydanDlaIndexu(item2);
                }
            }
        }

        private List<KalkulowanaOperacjaWydania> CzysaJuzDodaneOperacjeDlaTegoIndexu(string index)
        {
            List<KalkulowanaOperacjaWydania> wynik = new List<KalkulowanaOperacjaWydania>();

            foreach (var kalkulowana in listaKalkulowanychOperacji)
                if (kalkulowana.Index == index)
                    wynik.Add(kalkulowana);

            return wynik;
        }

    public class CzasyWydanVM : UserControl_ViewModelBase
    {
        private NastawyKalkulacjiCzasowWydan nastawy = new NastawyKalkulacjiCzasowWydan();
        private KryteriaDoboruOperacjiWydan zakresIndexowOrazOperacji = new KryteriaDoboruOperacjiWydan();
        private CzasScala czasDoPrzeliczaniaScala = new CzasScala(0, 0, 1, 5);
       
        public CzasyWydanVM(ObservableCollection<ArtykulScalaVM> kolekcja, ISmartReader reader) : base(kolekcja, reader)
        {
            NazwaViewModelu = nameof(CzasyWydanVM);
            kolekcjaArtykulowZaCheckowanychNaListViewNaOknieGlownym.CollectionChanged += SynchronizacjaPrzeliczaniaZacheckowanychArtykulow;
            listaKalkulowanychOperacji = new ObservableCollection<KalkulowanaOperacjaWydania>();
        }


        //(....)
        }
1

Nie rozumiem rozwiązania. Natomiast jeśli graf nie ma zbyt wiele wierzchołków <10k i trzymamy je w pamięci, to nie widzę problemu z przechodzeniem go rekurencyjnie za każdym razem gdy użytkownik wykona jakąś akcje. Tylko żeby to przechodzenie rekurencyjnie odwiedzało każdy wierzchołek tylko raz, robimy jakieś kolorowanie, albo wrzucamy już odwiedzone wierzchołki do jakiejś struktury która w maksymalnie logarytmicznym czasie nam odpowie czy zawiera dany wierzchołek czy nie.

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