2015-09-14 30 views
8

Tôi đã gặp khó khăn với vấn đề này trong vài ngày tới. Tôi đang cố tạo chức năng Pivot bằng cách sử dụng Luồng Java. Tôi chỉ phải triển khai SUM, COUNT, MAX, MIN và AVERAGE. Đối với đầu vào, tôi được cung cấp một chỉ mục cột Pivot, một mảng các chỉ mục hàng pivot và giá trị cần tính.Triển khai bảng Java Pivot bằng cách sử dụng Luồng

Điểm bắt giữ là dữ liệu nằm trong Danh sách < Danh sách < Đối tượng >>, Đối tượng có hoặc là Chuỗi, Số nguyên hoặc Đôi. nhưng tôi sẽ không biết cho đến khi chạy. Và tôi phải trả lại kết quả của mình dưới dạng Danh sách < Danh sách < Đối tượng >>.

Tôi gặp rắc rối với MAX/MIN (tôi giả sử trung bình mà sẽ tương tự như MAX và MIN)

Để trục trên nhiều giá trị bảng, tôi tạo ra một lớp học để sử dụng tôi groupingBy thứ hai của tôi

Điều này sẽ không biên dịch, tôi không chắc nên so sánh gì, ở đâu để chuyển đổi đối tượng sang int hoặc nếu tôi cần. Tôi muốn làm điều này tất cả với một dòng, nhưng tôi không chắc chắn nó có thể. Tôi đang làm gì sai, hoặc tôi có thể làm điều đó khác đi. Cảm ơn trước.

package pivot.test; 

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Collections; 
import java.util.Comparator; 
import java.util.List; 
import java.util.Map; 
import java.util.Optional; 
import java.util.stream.Collectors; 

public class PivotTest { 

    List<List<Object>> rows = new ArrayList<List<Object>>(); 

    public PivotTest() throws Exception { 

     rows.add(Arrays.asList(new Object[]{ "East", "Boy", "Tee", 10, 12.00})); 
     rows.add(Arrays.asList(new Object[]{ "East", "Boy", "Golf", 15, 20.00})); 
     rows.add(Arrays.asList(new Object[]{ "East", "Girl", "Tee", 8, 14.00})); 
     rows.add(Arrays.asList(new Object[]{ "East", "Girl", "Golf", 20, 24.00})); 
     rows.add(Arrays.asList(new Object[]{ "West", "Boy", "Tee", 5, 12.00})); 
     rows.add(Arrays.asList(new Object[]{ "West", "Boy", "Golf", 12, 20.00})); 
     rows.add(Arrays.asList(new Object[]{ "West", "Girl", "Tee", 15, 14.00})); 
     rows.add(Arrays.asList(new Object[]{ "West", "Girl", "Golf", 10, 24.00})); 

    } 

    // Dynamic Max based upon Column, Value to sum, and an array of pivot rows 
    public void MaxTable(int colIdx, int valueIdx, int... rowIdx) { 

     Map<Object, Map<Object, Integer>> myList = newRows.stream().collect(
     Collectors.groupingBy(r -> ((List<Object>) r).get(colIdx), 
     Collectors.groupingBy(r -> new PivotColumns(r, rowIdx), 
     Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingInt(???)), 
       r -> ((List<Object>) r).get(valueIdx))))); 

     System.out.println("Dynamic MAX PIVOT"); System.out.println(myList); 

    } 

    public static void main(String[] args) { 

     try { 
      PivotTest p = new PivotTest(); 
      System.out.println("\n\nStreams PIVOT with index values inside a List\n"); 
      p.MaxTable(0, 3, new int[] { 2 }); 
     } catch (Exception e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 

} 

class PivotColumns { 

    ArrayList<Object> columns; 

    public PivotColumns(
     List<Object> objs, int... pRows) { 
     columns = new ArrayList<Object>(); 

     for (int i = 0; i < pRows.length; i++) { 
      columns.add(objs.get(pRows[i])); 
     } 

    } 

    public void addObject(Object obj) { 
     columns.add(obj); 
    } 

    @Override 
    public int hashCode() { 
     final int prime = 31; 
     int result = 1; 
     result = prime * result + ((columns == null) ? 0 : columns.hashCode()); 
     return result; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (this == obj) 
      return true; 
     if (obj == null) 
      return false; 
     if (getClass() != obj.getClass()) 
      return false; 
     PivotColumns other = (PivotColumns) obj; 
     if (columns == null) { 
      if (other.columns != null) 
       return false; 
     } else if (!columns.equals(other.columns)) 
      return false; 
     return true; 
    } 

    public String toString() { 
     String s = ""; 
     for (Object obj : columns) { 
      s += obj + ","; 
     } 

     return s.substring(0, s.lastIndexOf(',')); 
    } 

} 
+0

Đó là câu hỏi * rất lớn *. Bạn có thể muốn đọc về cách đặt câu hỏi * Tối thiểu *. Xem http://stackoverflow.com/help/mcve --- Tôi đã không nhận được đến nay, nhưng bạn nói rằng bạn có một 'List' của các đối tượng, hoặc là' String', 'Integer', hoặc' Double' và rằng bạn sẽ không biết cho đến khi chạy, nhưng sau đó bạn tiếp tục hiển thị một lớp 'Row' được định nghĩa đầy đủ. Vì vậy, đó là nó, bạn có biết hay không? – Andreas

+0

Bất kỳ lý do cụ thể nào nó * có * là luồng? – Andreas

+0

No. Tôi hoàn toàn cởi mở với các giải pháp khác không liên quan đến luồng. –

Trả lời

3

Như tất cả các giá trị có thể (String, Integer, Double) được biết đến là Comparable, bạn có thể thực hiện một dàn diễn viên không được kiểm soát để giao diện Comparable. Cũng đừng quên giải nén tùy chọn. Cuối cùng nếu tôi hiểu đúng, kết quả nên Map<Object, Map<Object, Object>> myList, không Map<Object, Map<Object, Integer>> myList, như cột của bạn có thể có giá trị không nguyên:

public void MaxTable(int colIdx, int valueIdx, int... rowIdx) { 
    Map<Object, Map<Object, Object>> myList = newRows.stream().collect(
    Collectors.groupingBy(r -> r.get(colIdx), 
    Collectors.groupingBy(r -> new PivotColumns(r, rowIdx), 
    Collectors.collectingAndThen(Collectors.maxBy(
     Comparator.comparing(r -> (Comparable<Object>)(((List<Object>) r).get(valueIdx)))), 
     r -> r.get().get(valueIdx))))); 

    System.out.println("Dynamic MAX PIVOT"); System.out.println(myList); 
} 

Kết quả:

> p.MaxTable(0, 3, new int[] { 1 }); 
{West={Girl=15, Boy=12}, East={Girl=20, Boy=15}} 

> p.MaxTable(0, 4, new int[] { 1 }); 
{West={Girl=24.0, Boy=20.0}, East={Girl=24.0, Boy=20.0}} 

Như bạn thấy, bạn có thể xử lý cả hai IntegerDouble cột. Ngay cả String cũng có thể được xử lý (giá trị tối đa theo từ điển sẽ được chọn).

Đối với trung bình bạn có thể giả định rằng giá trị cột của bạn là những con số (Number lớp, hoặc Integer hoặc Double) và thu thập để Double (trung bình của các số nguyên có thể không nguyên cũng):

public void AverageTable(int colIdx, int valueIdx, int... rowIdx) { 
    Map<Object, Map<Object, Double>> myList = newRows.stream().collect(
      Collectors.groupingBy(r -> r.get(colIdx), Collectors 
        .groupingBy(r -> new PivotColumns(r, rowIdx), 
          Collectors.averagingDouble(r -> ((Number) (r 
            .get(valueIdx))).doubleValue())))); 

    System.out.println("Dynamic AVG PIVOT"); System.out.println(myList); 
} 

Output :

> p.AverageTable(0, 3, new int[] { 1 }); 
{West={Girl=12.5, Boy=8.5}, East={Girl=14.0, Boy=12.5}} 

> p.AverageTable(0, 4, new int[] { 1 }); 
{West={Girl=19.0, Boy=16.0}, East={Girl=19.0, Boy=16.0}} 
0

Với đầu vào là một List hàng, mỗi hàng là một List của cột, và cột là một String , Integer, hoặc Double, và không biết cái nào và số cột để nhóm theo, và không biết cái nào và loại cột nào để tổng hợp, tôi khuyên bạn nên triển khai tập hợp tổng hợp của riêng bạn.

Có thể, tất cả các hàng có cùng số cột và tất cả các giá trị của một cột nhất định sẽ luôn là cùng một loại (hoặc null).

gì bạn muốn nó cơ bản là một thực hiện Java của một SQL nhóm theo tuyên bố:

SELECT Column1, Column2, ... 
    , SUM(Column5), MIN(Column5), MAX(Column5), COUNT(Column5) 
    , SUM(Column6), MIN(Column6), MAX(Column6), COUNT(Column6) 
    , ... 
    FROM List<List<Object>> 
GROUP BY Column1, Column2, ... 

Bạn cần 3 lớp.Đầu tiên là lớp GroupBy, mà phải thực hiện equals()hashCode() như equals kết hợp/hashcode của nhóm bởi các cột: COLUMN1, column2, ...

Lớp thứ hai là Aggregator, mà thực sự là hai lớp thực hiện một giao diện chung, một lớp để tổng hợp Integer và một lớp khác để tổng hợp Double. Trình tổng hợp sẽ có một giá trị (Object) và sẽ tích lũy các giá trị tổng/phút/tối đa/đếm.

Lớp thứ ba là lớp chính, bạn gọi lớp học Pivot. Nó sẽ được thông báo về các cột nhóm mong muốn (có loại) và các cột tổng hợp mong muốn (có loại), tốt nhất là sử dụng builder pattern. Sau đó nó có thể được cung cấp dữ liệu, và sẽ thu thập dữ liệu đó trong một HashMap<GroupBy, Aggregator>, và sau đó chuyển đổi kết quả đó trở lại định dạng cần thiết cho giá trị trả lại.

Ví dụ về làm thế nào để gọi lớp Pivot:

List<List<Object>> input = /*constructed elsewhere*/; 

List<List<Object>> output = new Pivot() 
    .addGroupByString(0) // Column1 
    .addGroupByString(1) // Column2 
    .addGroupByInteger(2) // Column3 a group by column can be be a number 
    .addIntegerAggregation(4) // Column5 
    .addDoubleAggregation(5) // Column6 
    .process(input); 

Hoặc nếu bạn không phải lúc nào muốn tất cả quy tụ, nó có thể là:

 .addIntegerSum(4) // SUM(Column5) 
    .addDoubleMin(5) // MIN(Column6) 
    .addDoubleMax(5) // MAX(Column6) 

Với điều này, việc thực hiện Pivot thể xử lý bất kỳ số lượng nhóm nào theo cột và cột tổng hợp và việc sử dụng nó rất trực quan.

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