2017-12-15 171 views
6

Mam problem, który jestem pewien, że rozwiązanie jest takie proste, ale nie jestem w stanie go znaleźć. Mam ArrayList z mniejszych ArrayList s. Listy te zawierają elementy typu String. Chcę scalić mniejsze listy do jednego, a następnie usunąć duplikaty. Pozwól mi wyjaśnić.Usuwanie duplikatów z listy ArrayList of ArrayLists

mam to:

[[USA, Maine], [USA, Maine, Kennebunk], [USA, Maine, North Berwick], 
[USA, New Hampshire], [USA, Keene, New Hampshire], [USA, Keene, New 
Hampshire, Main Street], [USA, New Hampshire, Swanzey]]. 

To jest mój główny lista, która ma mniejsze list wewnątrz. Chcę mieć ostateczną wersję: ArrayList, która jest połączeniem mniejszych i powoduje usunięcie duplikatów.

Co chcę jest:

[USA, Maine, Kennebunk, North Berwick, New Hampshire , Keene, Main Street, Swanzey] 

Każda pomoc jest mile widziana. Dziękujemy

Odpowiedz

0

W przypadku kierowania na < Java 8 można utworzyć instancję ostatecznej wersji ArrayList, nazwijmy ją "ResultList". Następnie wykonaj iterację po każdym z wewnętrznych wewnętrznych ArrayLists i dodaj tylko te Strings, dla których metoda zwraca false. To jest rozwiązanie tylko wtedy, gdy użytkownik musi użyć ArrayList jako ostatecznego zbioru. W przeciwnym razie powinieneś rozważyć użycie HashSet, która automatycznie przechowuje unikalne wartości w środku i pozbywa się powtarzających się obiektów. Poniższy kod może pomóc trochę, jeśli trzeba użyć ArrayList jako swojej kolekcji Wynik:

ArrayList<ArrayList<String>> sourceList = new ArrayList<>(); 
     // Adding sample ArrayLists ("a" and "b") of Strings to sourceList: 
     ArrayList<String> a = new ArrayList<>(); 
     a.add("USA"); 
     a.add("Maine"); 
     sourceList.add(a); 
     ArrayList<String> b = new ArrayList<>(); 
     b.add("USA"); 
     b.add("Maine"); 
     b.add("Kennebunk"); 
     sourceList.add(b); 
     ArrayList<String> resultList = new ArrayList<>(); 
     for(ArrayList<String> outerList : sourceList) { 
      for(String str : outerList) { 
       // If resultList doesn't contain currently checked string... 
       if(!(resultList.contains(str))) { 
        // Add this string to resultList... 
        resultList.add(str); 
       } 
      } 
     } 
     System.out.println(resultList.toString()); 

Wyjście otrzymasz: [USA, Maine, Kennebunk]

+0

Tak, muszę użyć ArrayList jako mojej ostatecznej kolekcji. O kodzie masz jakieś pomysły? – hristoforidisc

+0

Można użyć dwóch zagnieżdżonych pętli foreach. W zewnętrznym, iterujesz nad zewnętrzną ArrayList, w wewnętrznej, iterujesz po każdej z wewnętrznych list. W korpusie pętli wewnętrznej sprawdzamy, czy ostatnia tablica ArrayList zawiera już łańcuch, a jeśli nie, dodajemy go do tablicy ArrayList –

3

Jest to łatwe do wykonania przy pomocy zestawów (zestaw nie pozwala duplikat wartości)

public List<String> merge(List<List<String>> list) { 
    Set<String> uniques = new HashSet<>(); 
    for(List<String> sublist : list) { 
     uniques.addAll(sublist); 
    } 
    return new ArrayList<>(uniques); 
} 

ps jeśli chcesz, aby połączyły Lista zostanie posortowana zmiany HashSet do TreeSet tak: Set<String> uniques = new TreeSet<>();

+0

. Zauważ, że 'TreeSet' używa _naturalnego porządkowania_ elementów (lub jakiegoś innego" Komparatora "przekazanego w czasie budowy) i _nie_ _insertion order_. Oznacza to, że wynik jest sortowany alfabetycznie, a nie jak w oryginalnych listach. – siegi

5

Jest to zwięzły rozwiązanie przy użyciu klasy Stream:

listOfLists.stream().flatMap(List::stream).collect(Collectors.toSet()) 

Zauważ, że wynik jest typu Set. To zajmuje się usuwaniem duplikatów.

Jeśli potrzebujesz List, można użyć tego:

listOfLists.stream() 
      .flatMap(List::stream) 
      .distinct() 
      .collect(Collectors.toList()) 

Zauważ, że nawet ten gwarantuje kolejność elementów jest stabilny, to znaczy [["foo","bar"],["bar","abc","foo"]] zawsze spowoduje ["foo","bar","abc"] w tej kolejności. Większość rozwiązań wykorzystujących Set nie gwarantuje tego, ponieważ większość z nich nie jest sortowana.

+0

Moja ArrayList of ArratLists jest nazywana filmowaniemLocations. Czy tak powinienem mieć kod? filmingLocations.stream(). FlatMap (List :: stream) .distinct(). Collect (Collectors.toList(); – hristoforidisc

+0

@hristoforidisc, yes :-) – siegi

+0

W tym miejscu flatMap (List :: stream) otrzymuję błąd. Czy mam coś importować? – hristoforidisc

0

Rozwiązanie:
Loop koryta kiedykolwiek String w was ArrayList z ArrayLists i dodać ciąg do innego ArrayList, jeśli nie znajduje się już na tej liście, stosując metodę .contains() z ArrayList

Kod:

public ArrayList<String> merge(ArrayList<ArrayList<String>> startArrayList) { 
    ArrayList<String> finalArrayList = new ArrayList<String>(); 
    //Iterate over each element 
    for (ArrayList<String> innerList:startArrayList) { 
     for (String value:innerList) { 
     //add the String if it is missing 
     if (!finalArrayList.contains(value)) 
      finalArrayList.add(value); 
     } 
    } 
    return finalArrayList; 
    } 
1

Tradycyjne rozwiązanie:

Set<String> result = new LinkedHashSet<>(); 
for (List<String> innerList : filmingLocations) result.addAll(innerList); 

Jako result jest LinkedHashSet, zachowuje porządek reklamowy, więc kolejność elementów będzie taka, jak na wewnętrznych listach.

Można również użyć równoważny Java 8 rozwiązanie:

Set<String> result = new LinkedHashSet<>(); 
filmingLocations.forEach(result::addAll); 

lub nawet Java 8 rozwiązanie strumieniowej:

Set<String> result = filmingLocations.stream() 
    .flatMap(List::stream) 
    .collect(Collectors.toCollection(LinkedHashSet::new)); 
+1

Dziękuję, wiedziałem, że w zamówieniu JDK zachowuje się jakaś 'Set', ale nigdy nie pamiętam jej nazwy (i nie wspominają o tym w Javadoc w' Collection' lub 'Set', podczas gdy robią to dla 'HashSet',' TreeSet', a nawet 'SortedSet') :-P – siegi

0

Widziałem ten post i musiał odpowiedzieć Berwick/Kennebunk to miasta, w których mieszkałem w Lol. Czy jesteś lokalny?

Anyways Najłatwiej to zrobić przy pomocy operacji ustawiania, jak wspomniano powyżej. To powoduje, że niektóre wyszukiwania O (log n).

public List<String> mergeTowns (List<List<String>> list) { 
    Set<String> uniques = new HashSet<>(); 
    for(List<String> sublist : list) { 
     uniques.addAll(sublist); 
    } 
    return new ArrayList<>(uniques); 
} 

Jeśli szukasz trochę bardziej dynamiczne struktury danych, korzystać z mapy, gdzie kraj jest Ci klucz i miasteczek są twoje wartości. W ten sposób, jeśli zdecydujesz się zbudować dużą bazę danych miast według krajów, w których jesteś, możesz, a następnie przeszukać mapę według kraju, aby wyświetlić miasta. Może używaj państwa zamiast kraju jako klucza.

Wynikowa struktura danych odda mapę podobną do tej. po wydrukowaniu.

[USA = [Berwick Kennebunk, północ Berwick studzienki] KANADA = [berwick, Kennebunk, North Berwick studzienki], Meksyk = [berwick, Kennebunk, North berwick, studnie]]

Drogą struktura danych została zbudowana, aby zapobiec powielaniu wpisów miast w tym samym kraju/stanie.

public class Merge { 


    private static ArrayList<String> mergeMap(HashMap<String, Set> map) { 
     ArrayList<String> data = new ArrayList(); 
     for(Entry<String, Set> entries : map.entrySet()){ 
      String country = entries.getKey(); 
      Set<String> towns = entries.getValue(); 
      data.add(country+" = "+towns); 
     } 
     return data; 
    } 



    public static void main(String[] args) { 
     //Mock data 
     String[] countrys = {"USA", "CANADA", "MEXICO"}; 

     //Try this way of building your data structure instead of an array list of array list. 
     HashMap<String,Set> map = new HashMap<String,Set>(); 
     TreeSet<String> towns = new TreeSet<String>(); 

     // Add a couple towns to your set of towns 
     towns.add("berwick"); 
     towns.add("north berwick"); 
     towns.add("kennebunk"); 
     towns.add("kennebunk"); 
     towns.add("kennebunk"); 
     towns.add("kennebunk"); 
     towns.add("wells"); 
     towns.add("wells"); 

     //With a map you could push a different set of towns to different countries 
     for(String country: countrys){ 
      map.put(country, towns); 
     } 

     //Pass in your map<Country, Towns> 
     ArrayList<String> mergedValues = mergeMap(map); 
    } 
}