2016-07-08 22 views
5

Có cách tiếp cận nào tốt hơn, đơn giản hơn cho vấn đề này không?Giao lộ luồng của bộ thành bộ mới

@Test 
public void testReduce() { 
    Set<Integer> foo = ImmutableSet.of(1,2,3,4,8,9); 
    Set<Integer> bar = ImmutableSet.of(1,3,8,5,11); 

    //DO think about solution for 1..n sets, and not only two. 
    Set<Integer> intersection = ImmutableList.of(foo,bar) 
      .stream() 
      .reduce(null, (a, b) -> { 
       if (a == null) { 
        a = new HashSet<Integer>(b); 
       } 
       else { 
        a.retainAll(b); 
       } 
       return a; 
      }); 
    assertThat(intersection, is(ImmutableSet.of(1,3,8))); 
} 
+1

http://stackoverflow.com/questions/31683375/java-8-lambda-intersection-of-two-lists – Wilson

+1

Thay vì 'ImmutableList.of (foo, bar) .stream()' bạn chỉ có thể sử dụng ' Stream.of (foo, bar) '… – Holger

+0

@Wilson: Tôi đã thấy câu hỏi đó. Tôi cần một giao lộ, chứ không phải hai bộ chỉ –

Trả lời

5

reduce là phương pháp sai cho điều này, vì bạn không được phép sửa đổi đối số của hàm cách này. Đây là một mutable giảm , còn được gọi là collect:

List<Set<Integer>> listOfSets=…; 
//check if at least one set is in the list 
Set<Integer> intersection = listOfSets.stream().skip(1) 
    .collect(()->new HashSet<>(listOfSets.get(0)), Set::retainAll, Set::retainAll); 

Có để peek cho các thiết lập đầu tiên được một trận hòa trở lại đây, nhưng sử dụng null như giá trị bản sắc là không sạch sẽ hoặc là (và sẽ không hoạt động với collect làm bộ tích lũy không thể trả lại bộ mới).

+0

Chà. Giải pháp tốt. Một câu hỏi: chúng tôi có thể bỏ qua phần tử đầu tiên từ luồng. Có thể không? –

+2

Vì vậy listOfSets.stream(). Skip (1) nên làm thủ thuật –

0

Bạn có thể lọc các yếu tố của foo bằng cách kiểm tra nếu họ đang ở bar hoặc otherBar thiết lập:

Set<Integer> set = 
    foo.stream().filter(e -> Stream.of(bar, otherBar).allMatch(s -> s.contains(e))).collect(toSet()); 

Ví dụ nếu bạn nhận được một Collection<Set<T>> như bạn đã nêu:

public static <T> Set<T> intersection(Collection<Set<T>> input) { 
    if(input.isEmpty()) { 
     return Collections.emptySet(); 
    } else { 
     Set<T> first = input.iterator().next(); 
     //if the collection allows to remove element, you can remove first before 
     return first.stream().filter(e -> input.stream().allMatch(s -> s.contains(e))).collect(toSet()); 
    } 
} 
+0

Trong ví dụ tôi có 2 bộ. Giải pháp sẽ hoạt động với bất kỳ số lượng phần tử nào và nên tránh tạo Bộ mới mỗi khi trình giảm tốc chạy. –

1

Câu trả lời này chỉ áp dụng cho tập hợp các số nguyên, không phải tập hợp chung. Nhưng đối với một người tìm kiếm tốc độ, đôi khi danh sách các số nguyên là một trường hợp tốt cho bitmap nén. Bạn nên kiểm tra xem nhóm nguyên của bạn độc đáo và trong một số trường hợp, bạn có thể giành chiến thắng vài bậc độ lớn vào tốc độ nếu bạn làm điều này (sử dụng com.googlecode.javaewah32, Apache 2.0):

Set<Integer> foo = ImmutableSet.of(1,2,3,4,8,9); 
    Set<Integer> bar = ImmutableSet.of(1,3,8,5,11); 

    EWAHCompressedBitmap32 fooBitmap = new EWAHCompressedBitmap32(); 
    EWAHCompressedBitmap32 barBitmap = new EWAHCompressedBitmap32(); 

    //fill bitmaps 
    foo.stream().forEach(fooBitmap::set); 
    bar.stream().forEach(barBitmap::set); 

    //fooBitmap.and(barBitmap) returns intersection of sets now. fast! 
    ImmutableSet<Integer> intersection = ImmutableSet.<Integer>builder() 
            .addAll(fooBitmap.and(barBitmap)) 
            .build(); 

    System.out.println(intersection); 

Mã này chỉ là một ví dụ. Bạn có thể/nên sử dụng một cách tiếp cận khác để chuyển đổi thành tập hợp kết quả. EWAHCompressedBitmap32Iterable<Integer> vì vậy, không có giới hạn về trí tưởng tượng.

Bây giờ, mã ở trên chỉ cắt 2 bộ. Để cắt tất cả các bộ trong danh sách, bạn có thể làm như thường lệ giảm:

Set<Integer> foo = ImmutableSet.of(1,2,3,4,8,9); 
    Set<Integer> bar = ImmutableSet.of(1,3,8,5,11); 

    List<Set<Integer>> sets = ImmutableList.of(foo,bar); 

    EWAHCompressedBitmap32 res = sets.stream().map(l -> { 
     EWAHCompressedBitmap32 b = new EWAHCompressedBitmap32(); 
     l.stream().forEach(b::set); 
     return b; 
    }).reduce(null, (l, r) -> l == null ? r : l.and(r)); 

    System.out.println(res); 

Tuy nhiên, thay thế khác là sử dụng giảm thu:

EWAHCompressedBitmap32 res = sets.stream().collect(Collectors.reducing(
     //identity 
     null, 
     //mapper set -> compressedBitmap 
     l -> { 
      EWAHCompressedBitmap32 b = new EWAHCompressedBitmap32(); 
      l.stream().forEach(b::set); 
      return b; 
     }, 
     //and-reducer 
     (l, r) -> l == null ? r : l.and(r) 
)); 
3

Sau đây sẽ có tác dụng nếu bạn sử dụng Eclipse Collections:

@Test 
public void testReduce() 
{ 
    ImmutableSet<Integer> foo = Sets.immutable.of(1, 2, 3, 4, 8, 9); 
    ImmutableSet<Integer> bar = Sets.immutable.of(1, 3, 8, 5, 11); 

    // Works with Eclipse Collections 7.0 or above 
    ImmutableSet<Integer> intersection1 = Lists.mutable.of(foo, bar) 
      .stream() 
      .reduce(ImmutableSet::intersect).get(); 
    Assert.assertEquals(intersection1, Sets.immutable.of(1, 3, 8)); 

    // Works with Eclipse Collections 8.0.0-M1 or above 
    ImmutableSet<Integer> intersection2 = Lists.immutable.of(foo, bar) 
      .reduce(ImmutableSet::intersect).get(); 
    Assert.assertEquals(intersection2, Sets.immutable.of(1, 3, 8)); 
} 

Điều này cũng có thể hoạt động với MutableSet.

@Test 
public void testReduce() 
{ 
    MutableSet<Integer> foo = Sets.mutable.of(1, 2, 3, 4, 8, 9); 
    MutableSet<Integer> bar = Sets.mutable.of(1, 3, 8, 5, 11); 

    // Works with Eclipse Collections 7.0 or above 
    MutableSet<Integer> intersection1 = Lists.mutable.of(foo, bar) 
      .stream() 
      .reduce(MutableSet::intersect).get(); 
    Assert.assertEquals(intersection1, Sets.immutable.of(1, 3, 8)); 

    // Works with Eclipse Collections 8.0.0-M1 or above 
    MutableSet<Integer> intersection2 = Lists.immutable.of(foo, bar) 
      .reduce(MutableSet::intersect).get(); 
    Assert.assertEquals(intersection2, Sets.immutable.of(1, 3, 8)); 
} 

Trong Eclipse Collections, ImmutableSet không mở rộng java.util.Set, như Set là một giao diện có thể thay đổi. MutableSet không mở rộng java.util.Set. Lựa chọn thiết kế này được giải thích trong câu trả lời cho số question này.

Lưu ý: Tôi là người cam kết cho Bộ sưu tập Eclipse.

+0

Ví dụ hay. Tôi sẽ xem Eclipse Collections. Nó có vẻ thú vị. –

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