2015-05-28 7 views
8

Ho una lista di liste:Trova il numero di elementi tra più elenchi e combina; rimuovere se/else complesso?

List<List<String>> someList = new List<List<>>(); 

La dimensione massima di una lista è cinque corde. E 'qualcosa di simile di seguito:

someList.get(0).size(); // 4 elements 
someList.get(1).size(); // 1 elements 
someList.get(2).size(); // 3 elements 
someList.get(3).size(); // 1 elements 
... 

Sto cercando di escogitare un metodo per creare un nuovo elenco di una dimensione specifica (1-5 elementi) mediante la combinazione di alcune delle liste nidificate di cui sopra. Avrei potuto fare qualcosa di simile al di sotto (in questo esempio, tre elementi):

public List<String> getThree() { 
    for (int j = 0; j < someList.size(); j++) { 
     //look for nested lists of size 3 
     if (someList.get(j).size() == 3) { 
      return someList.get(j); 
     } 
    for (int j = 0; j < someList.size(); j++) { 
     //if found nested list of size 2, find one of size 1 to combine 
     if (someList.get(j).size() == 2) { 
      for (int k = 0; k < someList.size(); k++) { 
       if (someList.get(k).size() == 1) { 
        return someList.get(j).add(someList.get(k).get(0)); 
       } 
      } 
     } 
    for (int j = 0; j < someList.size(); j++) { 
     //if found nested list of size 1, find one of size 2 to combine 
     if (someList.get(j).size() == 1) { 
      for (int l = 0; l < someList.size(); l++) { 
       if (someList.get(l).size() == 2) { 
        return someList.get(j).addAll(someList.get(l)); 
       } 
      } 
     } 
    } 
} 

Non ho incluso l'anello per se non sottoliste sono di dimensioni 2, per trovare tre di dimensioni 1, ma si può immaginare quanto lungo e quanto può essere brutto. L'ordine è importante, quindi i cicli for si incrementano sequenzialmente (cioè preferisco combinare la sottolista 1 + 2 in più di 2 + 3, 1 + 3 in più di 2 + 3, ecc.).

Spero di trovare un modo per implementarlo in modo dinamico. Posso solo capire quanto sia illeggibile e lungo il metodo getFive verrà fornita la mia attuale metodologia. Ho diversi metodi (getOne attraverso getFive), non ha bisogno di essere dinamico in questo senso, vorrei solo liberarmi di molti if/else e loop per ridurre la complessità e migliorare la leggibilità.

Devo dire che questo è il lavoro a casa, quindi non voglio una risposta specifica, ma una spinta nella giusta direzione. Qualcosa modulo forse? Per fare con i resti?

modifica; chiarire e dare un esempio:

aList = new List<String>; 
aList.add("a"); 
aList.add("b"); 
someList.add(aList); 
bList = new List<String>; 
bList.add("c"); 
someList.add(bList); 
newList = someList.getThree(); 
//newList.size() == 3 
//newList contains "a","b","c" 

Procedimento getThree() sta creando un nuovo elenco comprendente elementi delle sottoliste di someList. Non può dividere una sottolista (cioè non può prendere 1 elemento da una sottolista di 2 elementi), sta combinando intere sottoliste.

+0

Stai cercando di trasformare l'elenco degli elenchi in un unico elenco? Sto capendo questo giusto? – Forseth11

+1

Devo andare per circa un'ora, e se a questa domanda non viene data risposta, penso di avere una risposta per te. – Forseth11

+0

È importante quali liste combinate e quale ordine sono gli articoli? Supponiamo che tu abbia 'myList' con size' {1, 3, 2, 4, 1} ', e vuoi un elenco risultante di' size = 5', che tutte le seguenti combinazioni considerino le soluzioni? '{1 + 3 + 1}', '{3 + 2}', '{4 + uno 1}'. – mkobit

risposta

3

Se la tua intenzione è di continuare a collezionare da li successivi m fino ad ottenere 5 elementi, continuare ad aggiungere poi uscire quando l'elenco è completo:

public static List<String> fill(List<List<String>> sources, int size) { 
    List<String> list = new ArrayList<>(); 
    for (List<String> source : sources) 
     if (source.size() <= size - list.size()) 
      list.addAll(source); 
    return list; 
} 

Se si vuole consumare più grandi trovi i primi, aggiungere questa riga come la prima linea del metodo:

Collections.sort(sources, (a, b) -> b.size() - a.size()); 

in Java 8, molto succinta:

public static List<String> fill(List<List<String>> sources, int size) { 
    return sources.stream().reduce(new ArrayList<>(), 
     (a, b) -> {if (b.size() <= a.size() - size) a.addAll(b); return a;}); 
} 

e con il più basso-mod:

public static List<String> fill(List<List<String>> sources, int size) { 
    return sources.stream() 
     .sorted((a,b) -> b.size() - a.size()) 
     .reduce(new ArrayList<>(), (a, b) -> 
      {if (b.size() <= a.size() - size) a.addAll(b); return a;}); 
} 
+0

@ Shar1er80 Non me ne sono accorto. In realtà, tenere conto di ciò rende il codice molto più semplice. Pensi che il codice modificato faccia ciò che OP vuole ora? – Bohemian

+0

Mi piace la tua soluzione migliore, ora che penso di capire meglio le intenzioni dell'OP. Semplicemente non capisco lo scopo di restituire lo stesso risultato ogni volta che vengono effettuate le chiamate. Penso che la combinazione sia permanente e non temporanea perché sembra che tu possa avere condizioni in cui non vedrai mai una sottolista come parte del risultato restituito. – Shar1er80

+0

Ad esempio, nell'esempio di esempio dell'OP di {4, 1, 3, 1} ogni chiamata a un potenziale getOne() risulterà sempre nella sottolista all'indice 1 e la sottolista nell'indice 3 non verrà mai restituita. – Shar1er80

1

Poiché si specifica che la priorità della combinazione degli elenchi è da sinistra a destra. Un ciclo O (N^2) è sufficiente per gestire la combinazione di sottoliste per essere inferiore o uguale alla quantità desiderata.

public static void main(String[] args) throws Exception { 
    List<List<String>> someList = new ArrayList() {{ 
     add(new ArrayList() {{ 
      add("a1"); 
      add("a2"); 
     }}); 
     add(new ArrayList() {{ 
      add("b1"); 
     }}); 
     add(new ArrayList() {{ 
      add("c1"); 
      add("c2"); 
      add("c3"); 
     }}); 
     add(new ArrayList() {{ 
      add("d1"); 
     }}); 
    }}; 

    combine(someList, 4); 

    for(List<String> subList : someList) { 
     System.out.println(subList); 
    } 
} 

private static void combine(List<List<String>> someList, int combineAmount) { 
    for (int i = 0; i < someList.size(); i++) { 
     // Check if the current list already equals or exceeds the combineAmount 
     if (someList.get(i).size() >= combineAmount) { 
      continue; 
     } 

     // Add sublists to the current sublists until the size of the current 
     // sublist equals or exceeds the combineAmount 
     for (int j = i + 1; j < someList.size(); j++) { 
      if (someList.get(i).size() + someList.get(j).size() > combineAmount) { 
       continue; 
      } 
      someList.get(i).addAll(someList.get(j)); 
      someList.remove(j); 
      j--; 

      // Don't bother checking other sublists if the newly 
      // combined sublists equals or exceeds the combineAmount 
      if (someList.get(i).size() >= combineAmount) { 
       break; 
      } 
     } 
    } 
} 

Risultati (combineAmount = 4):

[a1, a2, b1, d1] 
[c1, c2, c3] 

Risultati (combineAmount = 2):

[a1, a2] 
[b1, d1] 
[c1, c2, c3] 

Risultati (combineAmount = 6):

[a1, a2, b1, c1, c2, c3] 
[d1] 
1

Da quello che ho capito, si desidera combinare un elenco di elenchi in un totale di 5 indici. Quando si esegue questa operazione, si desidera innanzitutto assegnare la priorità al lato sinistro.

Ecco un metodo che ho creato per farlo. So che non volevi un esempio specifico, ma penso che un esempio vi aiuterà a capire come aiutare gli altri che hanno anche questa domanda:

private static List<String> getListOf(List<List<String>> someList, int size) { 
    List<List<String>> combine = new ArrayList<List<String>>(); 
    List<List<String>> combinePrev = new ArrayList<List<String>>(); 
    int value = 0; 
    int indexCloseValue = 0; 
    int indexClose; 
    for(int i = 0; i < someList.size(); i++){//Loops through the lists 
     value = someList.get(i).size(); 
     boolean[] indexAdded = new boolean[someList.size()];//Used to make sure to not add duplicates 
     indexAdded[i] = true; 
     combine.add(someList.get(i));//add current loop to the combine list. 
     do{//A loop to try to add values other than the one of index i to equal size. This loops multiple times because it may take more than two to equal size. 
      indexCloseValue = 0; 
      indexClose = -1; 
      for(int j = 0; j < someList.size(); j++){ 
       if(!indexAdded[j]){ 
        int listSize = someList.get(j).size(); 
        if(value + listSize > indexCloseValue && value + listSize <= size){ 
         indexCloseValue = listSize; 
         indexClose = j; 
        } 
       } 
      } 
      if(indexClose == -1){ 
       break; 
      }else{ 
       combine.add(someList.get(indexClose)); 
       value+=indexCloseValue; 
       indexAdded[indexClose] = true; 
      } 
     }while(value + indexCloseValue < size); 
     int added = 0; 
     for(List<String> str : combine){//Check size of combine list 
      added+=str.size(); 
     } 
     int addedPrev = 0; 
     for(List<String> str : combinePrev){//Check size of combinePrev list 
      addedPrev+=str.size(); 
     } 
     if(added > addedPrev && added <= size){ 
      combinePrev = new ArrayList<List<String>>(combine);//Set combinePrev to combine if it is larger but less than size 
     } 
     combine = new ArrayList<List<String>>();//Reset combine 
    } 

    List<String> returnList = new ArrayList<String>(); 
    for(List<String> list : combinePrev){//converts double list to a single list of strings at length "size". 
     for(String str : list){ 
      returnList.add(str); 
     } 
    } 
    return returnList;  
} 

Se ci sono dei problemi con questo codice o avete una domanda chiedimi nei commenti

Problemi correlati