2015-06-09 48 views
5

Tôi đang đọc các số từ tệp .txt sử dụng BufferedReader. Tôi muốn đảo ngược thứ tự của các nguyên tố trong hơi nước này để khi chúng được thu thập chúng sẽ được sắp xếp từ cao nhất đến thấp nhất. Tôi không muốn sắp xếp sau khi mảng đã được xây dựng bởi vì tôi không biết có bao nhiêu phần tử trong đó, tôi chỉ cần các phần tử N cao nhất.Cách sắp xếp một IntStream theo thứ tự ngược lại

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

Nếu bạn biết bạn sẽ không có bất kỳ giá trị 'Integer.MIN_VALUE', bạn có thể thêm một bước để lập bản đồ ' i -> (-i) '. (Trình độ 'Integer.MIN_VALUE' là quan trọng, vì' Integer.MIN_VALUE == (- Integer.MIN_VALUE) '). – yshavit

+0

Ngoài ra, bạn có biết nếu combo sắp xếp được tối ưu hóa không? Bởi vì nếu không, sẽ có một cơ hội tốt để 'sắp xếp()' sẽ lưu trữ tất cả chúng trong bộ nhớ, trong trường hợp đó bạn cũng có thể lấy mảng đó và đọc N phần tử lớn nhất. – yshavit

+0

@yshavit Tôi nghĩ rằng bạn đang đúng về các combo sắp xếp giới hạn, nó phải lưu trữ nó trong một số container trung gian – Aurumae

Trả lời

3

Bởi vì thứ tự ngược lại không phải là trật tự tự nhiên, sorted() không thể được sử dụng để sắp xếp theo thứ tự ngược. Nếu bạn tránh IntStream, thay vào đó, hãy sử dụng Stream<Integer>, sau đó bạn có thể sử dụng Collections.reverseOrder() để sắp xếp luồng ngược lại theo thứ tự tự nhiên. Sau đó, bạn có thể gọi mapToInt và chuyển đổi thành int[] ở cuối.

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

Tôi nghĩ rằng 'i -> i' có thể là' Integer :: intValue', phải không? – yshavit

+0

@yshavit Có, 'Integer :: intValue' có thể thay thế' i -> i' ở đó. – rgettman

0

Thật khó để nói liệu .sorted().limit((long) N).toArray() sẽ được tối ưu hóa trong một số trường hợp (đó là thực hiện phụ thuộc nhưng được thực hiện hiện hành của Oracle, tôi sẽ không mong đợi nó), nhưng trong trường hợp đặc biệt này, suối nguồn là một dòng kích thước không xác định làm cho việc tối ưu hóa thậm chí ít có khả năng hơn.

Nếu bạn muốn ở bên an toàn, bạn có thể điều chỉnh this solution để nhận được n số lượng tối đa luồng một cách hiệu quả. Tất cả bạn phải làm là để đảo ngược thứ tự:

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); 
    }); 
} 

Sau đó, bạn có thể sử dụng nó như

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

Nhưng bạn không cần phải tạo ra một mảng như bạn có thể sử dụng tùy ý IntStream hoạt động trên kết quả . Giải pháp này sẽ giữ ở hầu hết các giá trị N, thậm chí ít hơn nếu có các bản sao vì nó chỉ giữ các giá trị riêng biệt và số lượng của chúng.

4

Cố gắng phủ nhận những giá trị trước khi phân loại và phủ nhận (trở lại bình thường) sau khi phân loại:

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

Bí quyết tuyệt vời, mặc dù bạn sẽ gặp vấn đề nếu đầu vào chứa 'Integer.MIN_VALUE'. –

+2

@TagirValeev Sau đó bạn có thể chuyển sang '.map (i-> ~ i)' thay vì '.map (i -> - i)'. –

+0

@ OlivierGrégoire, yup, tôi biết. Tôi đã sử dụng mẹo này trong [thư viện của tôi] (https://github.com/amaembo/streamex/blob/3824b54b798e2af8751088bdfd2205e1782644df/src/main/java/one/util/streamex/IntStreamEx.java#L431) gần một năm trước. –

Các vấn đề liên quan