Zliczanie duplikatów w kolekcji

0

Cześć

Zadałem już parę pytań na forum odnośnie kolekcji i finalnie chciałem napisać program, który pobiera dane z pliku txt i zlicza powtórzenia (docelowo mają być to nazwiska).
Ma to na celu nauczenie się posługiwania kolekcjami i przy okazji wyjściem/wejściem na pliku txt.
Mam problem, bo nie wiem jak rozwiązać kwestię przypisywania ilości powtórzeń do elementów w kolekcji. Napisałem takie coś:

public class Duplikaty
{   
    static int licznik = 0;   
    static LinkedHashSet<String> lista2 = new LinkedHashSet<String>();
    
    public static void main(String[] args)    

    {   
        liczenie();   
    }   

    public static void liczenie()   
    {   
        File plik = new File("test.txt");   
        File plik2 = new File("test.txt");   

        try   
        {   
        BufferedReader czytacz = new BufferedReader(new FileReader(plik));  
        BufferedReader czytacz2 = new BufferedReader(new FileReader(plik2));  

        String wiersz = null;  
        String wiersz2 = null; 

        ArrayList<String> lista = new ArrayList<String>();  
        LinkedHashSet<String> ts = new LinkedHashSet<String>(); 

        while((wiersz = czytacz.readLine()) != null)   
        {   
//            System.out.println(wiersz);  
            lista.add(wiersz);  
        }   

        while((wiersz2 = czytacz2.readLine()) != null) 
        { 
//            System.out.println(wiersz2); 
            ts.add(wiersz2); 
        } 
        Iterator<String> it = ts.iterator(); 

        for(int i = 0; i < lista.size(); i++)   
        {   
            it = ts.iterator(); 
            while(it.hasNext()) 
            { 
                if(lista.get(i).equals(it.next()))   
                {   
                    lista2.add(lista.get(i) + " " + licznik++);
                }   
            } 
        } 
        }   
        catch(Exception ex)   
        {   
            ex.printStackTrace();   
        }   

        for(String temp : lista2)
        {
        	System.out.println(temp);
        }
    }   
}   

Plik txt to:

test1
test2
test3
test4
test5
test1

Wynik jaki dostaję to:

test1 0
test2 1
test3 2
test4 3
test5 4
test1 5

Rozumiem czemu się tak dzieje ale nie wiem jak to poprawić, żeby otrzymać wynik podobny do tego:

test1 2
test2 1
test3 1
test4 1
test5 1

Może podchodzę kompletnie źle do tematu ale takie coś udało mi się napisać.
Chętnie przyjmę każdą krytykę i pomoc.

1

Używasz jednego licznika który inkrementujesz stąd taki wynik.
W set kopie nie są przechowywane więc ciężko byłoby liczyć w ten sposób który chcesz - użyj map.

0

A jak dodawać za każdym razem licznik nie znając wcześniej ilości elementów kolekcji?
Do głowy przychodzi mi skorzystanie z obiektów, gdzie każdy element kolekcji będzie nowym obiektem ze swoim licznikiem.

1

A czemu nie użyjesz mapy?

HashMap<String, Integer>

Wtedy String masz jako klucz (wyraz) a Integer to ilość wystąpień danego wyrazu.

Przykład:

private static HashMap<String, Integer> wordCount = new HashMap<>();

// Dodaje słowo do mapy
private static void add(String word) {
    if (wordCount.containsKey(word)) // Jeżeli słowo już istnieje
        wordCount.put(word, wordCount.get(word) + 1); // Dodaj 1 do ilości wystąpień
    else
        wordCount.put(word, 1); // Dodaj nowe słowo i ustaw 1 jako ilość wystąpień
}

Wystarczy czy przelecieć przez wszystkie wyrazy z pliku i użyć metody add aby je dodać do wordCount. Potem możesz wyświetlić za pomocą:

for (Map.Entry<String, Integer> entry : wordCount.entrySet()) {
    System.out.println(String.format("%s:%d", entry.getKey(), entry.getValue()));
}

Co wyświetla w takim formacie:

wyraz:ilość_wystąpień
wyraz:ilość_wystąpień
...
3

Generalnie od dawna nie trzeba używać pętli, liczników i flag, do takich zadań są streamy. Tutaj zadanie napisane za pomocą streama:

final Path path = Paths.get("C:\\Users\\test.txt");
Files.readAllLines(path).stream() // każda linijka jako element listy
                .map(e -> Arrays.asList(e.split(" "))) // podzielenie linijki na słowa
                .flatMap(Collection::stream) // zmergowanie streamów
                .collect(Collectors.groupingBy(e -> e, Collectors.counting())); // zgrupowanie słów po ilości wystąpień
3

Dla Listy stringów w Javie 8 możesz:

 List<String> list = new ArrayList<>();

Map<String, Long> counted = list.stream()
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
0

@atmal: Widzę, że napisałem dużo niepotrzebnego kodu. Twoje rozwiązanie było tym czego szukałem, teraz tylko dochodzę do wniosku, że książka do javy 1.5 była średnim pomysłem. Zainwestuje w jakąś książkę do javy 1.8.
Dziękuję za pomoc

0

// Java 8 style


list.stream().forEach(elem -> m.merge(elem, 1L, (a,b) -> a+b));



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