• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

powtorzenia obietow w arreylist java

Object Storage Arubacloud
0 głosów
207 wizyt
pytanie zadane 7 kwietnia 2023 w Java przez Davidxx Nowicjusz (190 p.)

Witam wszystkich

Mam  program obiektywny z 2 klasami, jedna klasa to pozycje w sklepie, druga to zamówienia. Mam problem z metoda dodajPozycje a dokładniej z powtorzeniem. Założenie jest takie, że jeśli dodam 2 takie same pozycje do zamówienia, to ma mi wyświetlać na liście zamowien to jako jedna pozycje, ze zwiększoną liczba sztuk . Próbowałem użyć !pozycje.contains (p) zeby nie dodowało powtorzeń do listy zamówień. Następnie w else porownywałem nazwe towaru i modyfikowałem liczbe sztuk w pozycji i nastepnie przy pomocy set zamieniałem odpowieni indeks arreylisty w zamowieniu. Działa tylko przy jednym powtorzeniu bo jeśli np dodam po raz 3 kawe do zamowienia to contains traktuje to jako nowy obiekt bo poprzednia kawa na lsicie ma inna wartosc sztuk . Nie mam już pomysłu jak mogę to rozwiązać , z góry dziekuje za jakąkolwiek pomoc. 

package zamówenie;

public class Main {
	public static void main (String[]args)  {

		Pozycja p1 = new Pozycja("Chleb", 1, 3.5);
		System.out.println(p1);
		Pozycja p2 = new Pozycja("Cukier", 3, 4);
		System.out.println(p2);
		Pozycja p3 = new Pozycja("kawa", 1, 13);
		System.out.println(p3);

		Zmowienie z = new Zmowienie(20);
		z.dodajPozycje(p1);
		z.dodajPozycje(p2);
		z.dodajPozycje(p2);
		z.dodajPozycje(p3);
		z.dodajPozycje(p3);
		z.dodajPozycje(p3);
		z.dodajPozycje(p3);
	//z.usunPozycje(3);
	//Pozycja zp1 = new Pozycja("cukier", 2, 7);
	//z.edytujPozycje(1,zp1);
		System.out.println(z);
	
	


	}
}

package zamówenie;

import java.util.Objects;

public class Pozycja {
private String nazwaTowaru;
@Override
public int hashCode() {
	return Objects.hash(cena, ileSztuk, nazwaTowaru);
}
@Override
public boolean equals(Object obj) {
	if (this == obj)
		return true;
	if (obj == null)
		return false;
	if (getClass() != obj.getClass())
		return false;
	Pozycja other = (Pozycja) obj;
	return Double.doubleToLongBits(cena) == Double.doubleToLongBits(other.cena) && ileSztuk == other.ileSztuk
			&& Objects.equals(nazwaTowaru, other.nazwaTowaru);
}


private int ileSztuk;
private double cena;

 Pozycja (String nazwaTowaru, int ileSztuk, double cena){
	 this.nazwaTowaru = nazwaTowaru;
		this.ileSztuk = ileSztuk;
		this.cena = cena;
		
 }
 public String getNazwaTowaru(){
		return this.nazwaTowaru;
 }
 public int getIleSztuk(){
		return this.ileSztuk;
	}
	
	public double getCena(){
		return this.cena;
	}
	
public double obliczWartosc() {
	
	return ileSztuk *cena;
}

public String toString() {
	return nazwaTowaru + "    " + cena +" zl           " + ileSztuk +  " szt.     " + obliczWartosc() + " zl "  ;
}
}

package zamówenie;

import java.util.ArrayList;
public class Zmowienie {
	
		int ileDodanych;
		int maksRozmiar ;
		ArrayList <Pozycja>  pozycje; 
		Zmowienie (){
			 this(10);
		  }

		Zmowienie(int maksRozmiar){
			this.maksRozmiar = maksRozmiar;
			this.pozycje = new ArrayList <>(maksRozmiar);
			this.ileDodanych = 0;
		}
		
		
		public void dodajPozycje(Pozycja p) {
			if (!pozycje.contains (p)) {
		
			if(pozycje.size()<maksRozmiar  ) {
			pozycje.add(p);
			ileDodanych++;
			}
			}
			else 
				for(int j =0; j<pozycje.size();j++ ) {
					if (pozycje.get(j).getNazwaTowaru().equals (p.getNazwaTowaru()) ){	
					
							int a = pozycje.get(j).getIleSztuk();
						a = a + p.getIleSztuk();
					Pozycja ppowielona = new Pozycja(p.getNazwaTowaru(),a, p.getCena());			
					pozycje.set(j,ppowielona );
			}
			}
			}
	
		void usunPozycje(int indeks) {
			pozycje.remove(indeks-1);
			ileDodanych--;
		}
		void edytujPozycje(int indeks,Pozycja p) {
			pozycje.set(indeks-1,p);
			return;
		}
		public double obliczWartosc() {
		double lacznie = 0.0;
	for(int i=0; i<ileDodanych; i++){
		lacznie += pozycje.get(i).obliczWartosc();
		}
	return lacznie;
		}
	public String toString() {
			String napis = "\nZamówienie:\n";
		for(int i=0; i<ileDodanych; i++){
		napis += (pozycje.get(i).toString()+"\n");
	}
		napis += "Razem: " + String.format("%.2f",obliczWartosc()) + " zł";
		return napis;
		}

}

 

2 odpowiedzi

+2 głosów
odpowiedź 8 kwietnia 2023 przez Wiciorny Ekspert (270,170 p.)
wybrane 9 kwietnia 2023 przez Davidxx
 
Najlepsza

Stwórz kolekcje mapy... która przechowuje wartość <Pozycja,Integer>  -> przyczym integer wskazuje na dokladna liczbe zapisana pod mape.
Następnie sprawdzając na mapie w metodzie dodawania... że jesli istnieje w mapie klucz dla Pozycja - np. sprawdzając po jej nazwie, to modyfikujesz aktualna wartość pod tym kluczem dodając +1, potem łatwo możesz modyfikować usunięcia itd itp. 


przykład: 
 

  final HashMap<Pozycja, Integer> testowo = new HashMap<String, Integer>;
  if(testowo.containsKey(obiektPozycja)) {
     testowo.put(obiektPozycja, testowo.get(obiektPozycja) + 1);
      // pobierz aktualna wartosc dla obiektuPozycja i dodaj do niej jeden
      // analogicznie mozesz usuwac w innej metodzie
   }

Uwaga! Mapa powinna być raczej własnościa zamówienia, tego jednego - tzn nie powinna być statyczna gdyz nie jest wspólna dla wszystkich zamówień, ale nie może być lokalna z racji tego, że powinna być częścią klasy zamówienia.
Klasyczny obiekt jako właściwość klasy. 

Zauważ, że potem z pomocą mapy możesz dowolnie w aplikacji : Wyświetlać ilość zamówień, usuwać, sprawdzać czy zamówienie istnieje, dodawać nowe, modyfikować itd. 
Z racji tego, że mapa może mieć tylko 1 wskazany klucz, to również pozbywasz się duplikatów. 

komentarz 9 kwietnia 2023 przez Davidxx Nowicjusz (190 p.)

 

wielkie dzięki :) wykorzystałem HashMap, ale zrobiłem trochę inaczej niż sugerowałeś, za klucz przyjąłem nazwę obiektu pozycji a wartością mapy był obiekt pozycji . Wszystko robiłem w metodzie dodaj pozycja , jeśli mapa nie zawierała nazwy obiektu to dodawałem do zamówienia nowy obiekt , w przeciwnym wypadku modyfikowałem już istniejący obiekt na mapie.

public void dodajPozycje(Pozycja p) {
		
			if(!listaZamowienia.containsKey(p.getNazwaTowaru())) {
				listaZamowienia.put(p.getNazwaTowaru(), p);
			
			}
			else  {
				int a = listaZamowienia.get(p.getNazwaTowaru()).getIleSztuk();
				a = a + p.getIleSztuk();
			Pozycja ppowielona = new Pozycja(p.getNazwaTowaru(),a, p.getCena());
			listaZamowienia.put(p.getNazwaTowaru(), ppowielona);
			}
		}

na końcu wartości mapy pobrałem i utworzyłem kolekcje  składającą się z obiektów, którą wyświetliłem

ArrayList<Pozycja> values  = new ArrayList<>(listaZamowienia.values());

 

0 głosów
odpowiedź 8 kwietnia 2023 przez DziQu Początkujący (420 p.)
Set działa na takiej zasadzie że podczas dodawania obiektu do setu jest wywoływana metoda equals w celu sprawdzenia czy jest już taki obiekt w secie.

Co możesz zrobić to zmodyfikować metode equals w klasie tak aby sprawdzała (najlepiej by było mieć ID w postaci Longa albo UUID jako główny klucz po którym te obiekty byłyby rozpoznawalne, ale na potrzeby tak prostego programu może być to String) czy dany obiekt istnieje już w secie, dzięki temu unikniesz momentu, w którym metoda .contains zwróci Ci false, ponieważ wtedy, będzie sprawdzana tylko nazwa produktu do porównania obiektu, a nie nazwa produktu wraz z ilością, co da ci oczekiwany rezultat.
komentarz 8 kwietnia 2023 przez Davidxx Nowicjusz (190 p.)

ok dzieki , bede próbował . W miedzy czasie zrobiłem coś takiego :

public void dodajPozycje(Pozycja p) {
			if (!pozycje.contains (p) && !kontrolna.contains (p)) {
		
			if(pozycje.size()<maksRozmiar  ) {
			pozycje.add(p);
			kontrolna.add(p);
			ileDodanych++;
			}
			}
			else 
				for(int j =0; j<pozycje.size();j++ ) {
					if (pozycje.get(j).getNazwaTowaru().equals (p.getNazwaTowaru()) ){	
					
							int a = pozycje.get(j).getIleSztuk();
						a = a + p.getIleSztuk();
					Pozycja ppowielona = new Pozycja(p.getNazwaTowaru(),a, p.getCena());			
					pozycje.set(j,ppowielona );
			}
			}
			}

dodałem druga listę która nie jest modyfikowana i podwójny warunek  z contains . Wszystko działa i dobrze sumuje, ale wydaje mi się, że nie powinno się tego tak robić .

1
komentarz 8 kwietnia 2023 przez Wiciorny Ekspert (270,170 p.)
Co do Setu, to  z racji tego, że mamy specjalne warunki metody equals nie można wybrać sobie 1 klucza do tworzenia tej metody więc to nie ma prawa tak działać..

Generalnie, żeby umożliwić porównywanie obiektu po określonym typie ( tego nie robi equals, więc kolega źle mówi, gdyż equals musi działać i powinien na bazie jednoznaczności obiektów, więc po wszystkich polach :) i nawet uwzględnił bym hashCode do  wyliczenia), najlepiej aby klasa mogła zaimplementować interfejs Comparable albo Comparator i w metodzie ktora musi zostać zaimplementowana, napiszesz swoja logikę, potem niezależnie od ilosci danych, traktujesz je jako kolekcje np listy, mapy ( strumienia z danymi) i ten strumień po prostu robisz collect, czyli zbierasz z określonym comparatorem, albo filtrujesz dane dla kolekcji - jesli kolekcja implementuje któryś z interfejsow to, tez mozesz to wykorzystać jako po prostu filter w strumieniu danych i  posyłasz odpowiedni komparator i twoją kolekcje, możesz zdefiniować wiele rodzajów porównania i wybierać w danym momencie jaki chcesz. Np. dyktowany przez użytkownika
Warto pamiętać że Comparator w takim wypadku musi być predykatem aby był dostępny w lazy evaluating.

Po drugie  jest zasada która jednoznacznie określa to w jaki sposób nadpisywanie equals ma być robione i nie można definiować sobie "po kluczu, bo właściwościwości konkretnej tej jednej"  
https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)
komentarz 9 kwietnia 2023 przez DziQu Początkujący (420 p.)

Oczywiście że ma prawo tak działać, nie twierdzę że to podejście jest okej, bo istnieją pewne reguły co do definiowania metod equals i hashcode,

Mimo wszystko nadal twierdze że to co napisałem jest prawdą i tak działa, a o to mały test:

 

        Product product1 = new Product("Maslo", 1);
        Product product2 = new Product("Maslo", 2);
        Product product3 = new Product("Maslo", 3);
        Product product4 = new Product("Maslo", 4);
        Product product5 = new Product("Maslo", 5);

        Set<Product> products = new HashSet<>();
        products.add(product1);
        products.add(product2);
        products.add(product3);
        products.add(product4);
        products.add(product5);

        products.forEach(System.out::println);

Jest to moment w ktorym equals jest zdefiniowany na pole "nazwa" (1 parametr konstruktora), wynik wykonania:
 

Product{nazwa='Maslo', ilosc=1}

Process finished with exit code 0


Teraz jesli zdefiniuje equals na pole nazwa oraz ilosc, to wynik programu jest następujący:

Product{nazwa='Maslo', ilosc=2}
Product{nazwa='Maslo', ilosc=1}
Product{nazwa='Maslo', ilosc=4}
Product{nazwa='Maslo', ilosc=3}
Product{nazwa='Maslo', ilosc=5}

Process finished with exit code 0

Ale mimo wszystko popieram Twoje rozwiązanie na zasadzie Comparatora.
 

komentarz 9 kwietnia 2023 przez Wiciorny Ekspert (270,170 p.)

Po pierwsze najwazniejsze, nie możesz redefiniować equals jak chcesz, gdyż jak Ci napisałem w javie według dokumentacji, equals ma specjalne warunki tego jak powinna być implementowana to jedno i to było przyczyną mojego czepiania się.
Po drugie, nie ma możliwości rozróżnienia obiektów, po tym, czym chce w danym momencie np. wybieram z filtru w aplikacji.
Wynik jest niepoprawny 

Product{nazwa='Maslo', ilosc=1}

Powinienem mieć masło w ilości takiej ile razy został dodany :) i o to chodzi. 
Co jeśli wezmę 2 takie same masła, tej samej marki? Twoje equals narusza wtedy integralność, gdyż to są dwa różne obiekty niezmienne, w tej samej ilości i tej samej marki 

I czepiam się, bo łamanie takiej podstawowej zasady, jakby ktoś startujący do pracy na juniora powiedział na rozmowie o dowolnym i bezwarunkowym ingerowaniu w equals, to z automatu tej pracy nie dostanie, bo już widac, że traci podstawową zasadę, czym obiekt jest, czym jest jego stan i co rozróżnia go jako integralny i "independent "

Tylko, że widzisz nawet jeśli produkt Masło- z ilością 5 jest innym obiektem z punktu widzenia paradygmatu niż Masło z ilością 4, w dwóch przykładach ani razu nie działa poprawnie to, co chciał osiągnąć autor i nie ma to logiki, dlaczego skoro dodaje produkty :) takie same, nadal mam 1 produkt, albo nie mam. 

Comparator, też po złym zrozumieniu celu autora, nie jest potrzebny, dlatego to też był mój błąd, bo zrozumiałem to jako inny kontekst. 

 

Podobne pytania

0 głosów
1 odpowiedź 103 wizyt
pytanie zadane 1 listopada 2020 w C i C++ przez forvev Początkujący (390 p.)
+1 głos
1 odpowiedź 121 wizyt
pytanie zadane 11 stycznia w Java przez Specjalny Nowicjusz (230 p.)
0 głosów
1 odpowiedź 135 wizyt
pytanie zadane 20 maja 2023 w Java przez Danny26 Nowicjusz (220 p.)

92,575 zapytań

141,425 odpowiedzi

319,650 komentarzy

61,961 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...