2015-06-09 12 views
5

Czytam w liczbach z pliku .txt przy użyciu BufferedReader. Chcę odwrócić kolejność elementów w tej parze, tak aby po ich zebraniu zostały one rozmieszczone od najwyższego do najniższego. Nie chcę sortować po zbudowaniu tablicy, ponieważ nie mam pojęcia, ile elementów może w niej być, potrzebuję tylko najwyższych N elementów.Jak sortować IntStream w odwrotnej kolejności

in = new BufferedReader(reader); 
       int[] arr = in.lines() 
         .mapToInt(Integer::parseInt) 
         .sorted() 
         .limit((long) N) 
         .toArray(); 
+0

Jeśli wiesz, że nie będzie miał żadnych 'wartości Integer.MIN_VALUE', można dodać do mapy krok' i -> (-i) '. (Kwalifikacja 'Integer.MIN_VALUE' jest ważna, ponieważ' Integer.MIN_VALUE == (- Integer.MIN_VALUE) '). – yshavit

+0

Czy wiesz, że kombinacja limitu sortowania jest zoptymalizowana? Bo jeśli nie, istnieje duża szansa, że ​​'sorted()' i tak zapisze je wszystkie w pamięci, w takim przypadku możesz równie dobrze pobrać tę tablicę i przeczytać N najwspanialszych elementów. – yshavit

+0

@yshavit Myślę, że masz rację co do limitu sortowania, musisz go przechowywać w jakimś pośrednim pojemniku. – Aurumae

Odpowiedz

3

Ponieważ odwrotnej kolejności nie jest naturalną kolejność, sorted() nie może być użyte do sortowania w odwrotnej kolejności. Jeśli unikniesz parametru IntStream, używając zamiast tego Stream<Integer>, możesz użyć parametru Collections.reverseOrder(), aby posortować strumień w odwrotnej kolejności. Następnie możesz zadzwonić pod numer mapToInt i przekonwertować na koniec na int[].

int[] arr = in.lines() 
      .map(Integer::valueOf) // Extract Integer, not int 
      .sorted(Collections.reverseOrder()) // On Stream<Integer> 
      .limit(N) 
      .mapToInt(i -> i)  // map Integer to int 
      .toArray(); 
+0

Myślę, że 'i -> i' może być' Integer :: intValue', prawda? – yshavit

+0

@yshavit Tak, 'Integer :: intValue' może zastąpić' i -> i'. – rgettman

0

Trudno powiedzieć, czy .sorted().limit((long) N).toArray() dostanie zoptymalizowane w niektórych przypadkach (jest zależna od implementacji, ale biorąc pod uwagę obecną realizację Oracle, nie będę go oczekiwać), ale w tym szczególnym przypadku, strumień źródłem jest strumień nieznany rozmiar, który sprawia, że ​​optymalizacja jest jeszcze mniej prawdopodobna.

Jeśli chcesz być na bezpiecznej stronie, można dostosować this solution dla coraz n maksymalną liczbę strumienia sprawnie. Wszystko co musisz zrobić, to odwrócić kolejność:

public static IntStream maxValuesDescending(IntStream source, int limit) { 
    TreeMap<Integer,Integer> m=new TreeMap<>(Comparator.reverseOrder()); 
    source.forEachOrdered(new IntConsumer() { 
     int size, min=Integer.MIN_VALUE; 
     public void accept(int value) { 
      if(value<min) return; 
      m.merge(value, 1, Integer::sum); 
      if(size<limit) size++; 
      else m.compute(min=m.lastKey(), (k,count)->count==1? null: count-1); 
     } 
    }); 
    if(m.size()==limit)// no duplicates 
     return m.keySet().stream().mapToInt(Integer::valueOf); 
    return m.entrySet().stream().flatMapToInt(e->{ 
     int value = e.getKey(), count = e.getValue(); 
     return count==1? IntStream.of(value): IntStream.range(0, count).map(i->value); 
    }); 
} 

Wtedy można go używać jak

int[] arr = maxValuesDescending(in.lines().mapToInt(Integer::parseInt), N).toArray(); 

Ale nie są wymagane do utworzenia tablicy, jak można użyć dowolnych IntStream operacji na wynik . To rozwiązanie będzie zawierać najwyżej wartości N, a nawet mniej, jeśli istnieją duplikaty, ponieważ zawiera tylko różne wartości i ich liczbę.

4

Spróbuj negując wartości przed sortowaniem i negacji (wraca do normy) po sortowaniu:

in = new BufferedReader(reader); 
int[] arr = in.lines() 
       .mapToInt(Integer::parseInt) 
       .map(i -> -i).sorted().map(i -> -i) 
       .limit((long) N) 
       .toArray(); 
+2

Fajna sztuczka, chociaż będziesz mieć problemy, jeśli dane wejściowe zawierają "Integer.MIN_VALUE". –

+2

@TagirValeev Możesz wtedy po prostu zmienić na '.map (i-> ~ i)' zamiast '.map (i -> - i)'. –

+0

@ OlivierGrégoire, tak, wiem. Użyłem tej sztuczki w [mojej bibliotece] (https://github.com/amaembo/streamex/blob/3824b54b798e2af8751088bdfd2205e1782644df/src/main/java/one/util/streamex/IntStreamEx.java#L431) prawie rok temu. –

Powiązane problemy