2014-04-05 17 views
5

मैं लैम्ब्डा अभिव्यक्ति का उपयोग करके सामान्य आंकड़ों को लागू करने वाली एक साधारण कक्षा बनाना चाहता हूं। मैं सोच रहा हूं कि मैं सांख्यिकीय() विधि में स्विच केस का उपयोग कैसे कर सकता हूं?जावा 8 रिमैक्टरिंग लैम्ब्डा एक्सप्रेशन

उदाहरण के लिए, मैं आदि सूची का विचरण,

धन्यवाद गणना करने के लिए एक नया लैम्ब्डा लिखने के लिए कर सकते हैं।

public class DescriptiveStatistics { 

    public static void main(String[] args) { 
     List<Double> numbers = Arrays.asList(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0); 
     numbers.stream().forEach(n-> System.out.print(n + " ")); 
     System.out.println(); 
     System.out.println("Descriptive statistics"); 
     System.out.println("Sum: " + statistic(numbers, "Sum")); 
     System.out.println("Max: " + statistic(numbers, "Max")); 
     System.out.println("Min: " + statistic(numbers, "Min")); 
     System.out.println("Average: " + statistic(numbers, "Average")); 
     System.out.println("Count: " + statistic(numbers, "Count")); 
    } 

    private static double statistic(List<Double> numbers, String function) { 
     switch (function.toLowerCase()) { 
      case "sum": 
       return numbers.stream().mapToDouble(Double::doubleValue).sum(); 
      case "max": 
       return numbers.stream().mapToDouble(Double::doubleValue).max().getAsDouble(); 
      case "min": 
       return numbers.stream().mapToDouble(Double::doubleValue).min().getAsDouble(); 
      case "average": 
       return numbers.stream().mapToDouble(Double::doubleValue).average().getAsDouble(); 
      case "count": 
       return numbers.stream().mapToDouble(Double::doubleValue).count(); 
     } 
     return 0; 
    } 

मैं इस

private static double newStatistics(List<Double> numbers, Function<Double, Double> function){ 
     return numbers.stream().mapToDouble(Double::doubleValue).function(); 
    } 
+0

आप का उपयोग करना चाहिए या तो एक 'enum' (यदि आप समय से आगे सभी कार्यों को पता है) या एक रणनीति इंटरफ़ेस (यदि आपको रनटाइम पर नए प्लग करने में सक्षम होना चाहिए)। – chrylis

+0

मुझे लगता है कि रणनीति इंटरफेस सवाल का जवाब देता है। धन्यवाद! – CheJharia

उत्तर

11

क्यों नहीं बस DoubleStream#summaryStatistics का उपयोग करें या एक समान पैटर्न लागू होते हैं:

private static double statistic(List<Double> numbers, 
           ToDoubleFunction<DoubleStream> function) { 
    return function.applyAsDouble(
     numbers.stream().mapToDouble(Double::doubleValue)); 
} 

अब, आप विधि, के रूप में इस प्रकार धारा पर विभिन्न कार्यों के लिए एक स्विच बयान का उपयोग किए बिना आह्वान कर सकते हैं?

तुम भी कस्टम तरीकों को जोड़ने के लिए वर्ग का विस्तार, का कहना है कि एक विचरण, तिरछापन और उदाहरण के लिए कुकुदता सकता है:

/** 
* Algorithms derived from: Philippe Pébay, Formulas for Robust, One-Pass Parallel 
* Computation of Covariances and Arbitrary-Order Statistical Moments. 
*/ 
public class MoreDoubleStatistics extends DoubleSummaryStatistics { 

    private double M1, M2, M3, M4; 

    @Override 
    public void accept(double x) { 
     super.accept(x); 

     long n = getCount(); 

     double delta = x - M1;      // δ 
     double delta_n = delta/n;     // δ/n 
     double delta2_n = delta * delta_n;   // δ^2/n 
     double delta2_n2 = delta_n * delta_n;  // δ^2/n^2 
     double delta3_n2 = delta2_n * delta_n;  // δ^3/n^2 
     double delta4_n3 = delta3_n2 * delta_n;  // δ^4/n^3 

     M4 += (n - 1) * (n * n - 3 * n + 3) * delta4_n3 
       + 6 * M2 * delta2_n2 
       - 4 * M3 * delta_n; 
     M3 += (n - 1) * (n - 2) * delta3_n2 
       - 3 * M2 * delta_n; 
     M2 += (n - 1) * delta2_n; 
     M1 += delta_n; 
    } 

    @Override 
    public void combine(DoubleSummaryStatistics other) { 
     throw new UnsupportedOperationException(
       "Can't combine a standard DoubleSummaryStatistics with this class"); 
    } 

    public void combine(MoreDoubleStatistics other) { 
     MoreDoubleStatistics s1 = this; 
     MoreDoubleStatistics s2 = other; 

     long n1 = s1.n(); 
     long n2 = s2.n(); 
     long n = n1 + n2; 

     double delta = s2.M1 - s1.M1;    // δ 
     double delta_n = delta/n;     // δ/n 
     double delta2_n = delta * delta_n;   // δ^2/n 
     double delta2_n2 = delta_n * delta_n;  // δ^2/n^2 
     double delta3_n2 = delta2_n * delta_n;  // δ^3/n^2 
     double delta4_n3 = delta3_n2 * delta_n;  // δ^4/n^3 

     this.M4 = s1.M4 + s2.M4 + n1 * n2 * (n1 * n1 - n1 * n2 + n2 * n2) * delta4_n3 
       + 6.0 * (n1 * n1 * s2.M2 + n2 * n2 * s1.M2) * delta2_n2 
       + 4.0 * (n1 * s2.M3 - n2 * s1.M3) * delta_n; 

     this.M3 = s1.M3 + s2.M3 + n1 * n2 * (n1 - n2) * delta3_n2 
       + 3.0 * (n1 * s2.M2 - n2 * s1.M2) * delta_n; 

     this.M2 = s1.M2 + s2.M2 + n1 * n2 * delta2_n; 

     this.M1 = s1.M1 + n2 * delta; 

     super.combine(other); 
    } 

    private long n() { return getCount(); } 

    public double mean() { return getAverage(); } 
    public double variance() { return n() <= 1 ? 0 : M2/(n() - 1); } 
    public double stdDev() { return sqrt(variance()); } 
    public double skew() { return M2 == 0 ? 0 : sqrt(n()) * M3/ pow(M2, 1.5); } 
    public double kurtosis() { return M2 == 0 ? 0 : n() * M4/(M2 * M2) - 3.0; } 
} 
+0

क्या आप एक गठबंधन समारोह के लिए कोड प्रदान कर सकते हैं, ताकि इस वर्ग को कलेक्टर के रूप में उपयोग किया जा सके? –

+0

लेकिन फिर अंतिम परिणाम में स्क्व्यू और कुर्टोसिस भिन्न नहीं होगा? मेरा मतलब है डबलसमरीस्टैटिक्स :: गठबंधन उन्हें ध्यान में नहीं लेता है, या क्या मुझे कुछ याद आ रही है? –

+0

@ रोलैंड गॉड अच्छा बिंदु आप बिल्कुल सही हैं। संपादित। – assylias

8

की तरह एक विधि के मन में है एक समारोह प्रकार, कि एक DoubleStream और रिटर्न लेता है के साथ विधि के स्ट्रिंग पैरामीटर आंकड़ा बदलें कुल

System.out.println("Sum: " + statistic(numbers, s -> s.sum())); 
System.out.println("Max: " + statistic(numbers, s -> s.max().getAsDouble())); 
System.out.println("Min: " + statistic(numbers, s -> s.min().getAsDouble())); 
System.out.println("Average: " + statistic(numbers, s -> s.average().getAsDouble())); 
System.out.println("Count: " + statistic(numbers, s -> s.count())); 
+1

धन्यवाद। और मैं अपना खुद का ToDoubleFunction() बनाने के बारे में और कहां पढ़ सकता हूं? उदाहरण के लिए, भिन्नता की गणना के लिए। – CheJharia

+0

's -> s.sum()' के बजाय, आप इसे 'डबलस्ट्रीम :: योग' तक सरल बना सकते हैं। 'S-> s.count()' के लिए चला जाता है। – bcsb1001

+0

@ बीसीएसबी 1001: मेरी राय में, 's-> s.sum()' 'DoubleStream :: sum' (पठनीयता और रखरखाव के संबंध में) से सरल है। – nosid

संबंधित मुद्दे