স্ট্রিম ব্যবহার করে বিগডিসিমাল যুক্ত করা


178

আমার কাছে বিগডিসিমালসের একটি সংকলন রয়েছে (এই উদাহরণে, ক LinkedList) যা আমি একসাথে যুক্ত করতে চাই। এর জন্য স্ট্রিম ব্যবহার করা কি সম্ভব?

আমি লক্ষ করেছি Streamক্লাসের বিভিন্ন পদ্ধতি রয়েছে

Stream::mapToInt
Stream::mapToDouble
Stream::mapToLong

যার প্রতিটি একটি সুবিধাজনক sum()পদ্ধতি আছে। তবে, যেমনটি আমরা জানি, floatএবং doubleগণিত প্রায় সবসময়ই একটি খারাপ ধারণা।

সুতরাং, বিগডিসিমালগুলি যোগ করার কোনও সুবিধাজনক উপায় আছে কি?

আমার এখন পর্যন্ত এই কোডটি।

public static void main(String[] args) {
    LinkedList<BigDecimal> values = new LinkedList<>();
    values.add(BigDecimal.valueOf(.1));
    values.add(BigDecimal.valueOf(1.1));
    values.add(BigDecimal.valueOf(2.1));
    values.add(BigDecimal.valueOf(.1));

    // Classical Java approach
    BigDecimal sum = BigDecimal.ZERO;
    for(BigDecimal value : values) {
        System.out.println(value);
        sum = sum.add(value);
    }
    System.out.println("Sum = " + sum);

    // Java 8 approach
    values.forEach((value) -> System.out.println(value));
    System.out.println("Sum = " + values.stream().mapToDouble(BigDecimal::doubleValue).sum());
    System.out.println(values.stream().mapToDouble(BigDecimal::doubleValue).summaryStatistics().toString());
}

আপনি দেখতে পাচ্ছেন যে, আমি বিগডিসিমালগুলি ব্যবহার করে সংক্ষিপ্ত করছি BigDecimal::doubleValue(), তবে এটি (প্রত্যাশিত হিসাবে) সুনির্দিষ্ট নয়।

উত্তর উত্তর পোস্ট করুন

উভয় উত্তর অত্যন্ত সহায়ক ছিল। আমি কিছুটা যুক্ত করতে চেয়েছিলাম: আমার বাস্তব জীবনের দৃশ্যে কাঁচা সংগ্রহ করা জড়িত না BigDecimal, সেগুলি একটি চালানে জড়িত । তবে, আমি map()স্ট্রিমের জন্য ফাংশনটি ব্যবহার করে আমান অগ্নিহোত্রীর জবাবদিহিটি পরিবর্তন করতে পেরেছিলাম :

public static void main(String[] args) {

    LinkedList<Invoice> invoices = new LinkedList<>();
    invoices.add(new Invoice("C1", "I-001", BigDecimal.valueOf(.1), BigDecimal.valueOf(10)));
    invoices.add(new Invoice("C2", "I-002", BigDecimal.valueOf(.7), BigDecimal.valueOf(13)));
    invoices.add(new Invoice("C3", "I-003", BigDecimal.valueOf(2.3), BigDecimal.valueOf(8)));
    invoices.add(new Invoice("C4", "I-004", BigDecimal.valueOf(1.2), BigDecimal.valueOf(7)));

    // Classical Java approach
    BigDecimal sum = BigDecimal.ZERO;
    for(Invoice invoice : invoices) {
        BigDecimal total = invoice.unit_price.multiply(invoice.quantity);
        System.out.println(total);
        sum = sum.add(total);
    }
    System.out.println("Sum = " + sum);

    // Java 8 approach
    invoices.forEach((invoice) -> System.out.println(invoice.total()));
    System.out.println("Sum = " + invoices.stream().map((x) -> x.total()).reduce((x, y) -> x.add(y)).get());
}

static class Invoice {
    String company;
    String invoice_number;
    BigDecimal unit_price;
    BigDecimal quantity;

    public Invoice() {
        unit_price = BigDecimal.ZERO;
        quantity = BigDecimal.ZERO;
    }

    public Invoice(String company, String invoice_number, BigDecimal unit_price, BigDecimal quantity) {
        this.company = company;
        this.invoice_number = invoice_number;
        this.unit_price = unit_price;
        this.quantity = quantity;
    }

    public BigDecimal total() {
        return unit_price.multiply(quantity);
    }

    public void setUnit_price(BigDecimal unit_price) {
        this.unit_price = unit_price;
    }

    public void setQuantity(BigDecimal quantity) {
        this.quantity = quantity;
    }

    public void setInvoice_number(String invoice_number) {
        this.invoice_number = invoice_number;
    }

    public void setCompany(String company) {
        this.company = company;
    }

    public BigDecimal getUnit_price() {
        return unit_price;
    }

    public BigDecimal getQuantity() {
        return quantity;
    }

    public String getInvoice_number() {
        return invoice_number;
    }

    public String getCompany() {
        return company;
    }
}

উত্তর:


354

আসল উত্তর

হ্যাঁ, এটি সম্ভব:

List<BigDecimal> bdList = new ArrayList<>();
//populate list
BigDecimal result = bdList.stream()
        .reduce(BigDecimal.ZERO, BigDecimal::add);

এটি যা করে তা হ'ল:

  1. প্রাপ্ত a List<BigDecimal>
  2. এটিকে পরিণত করুন Stream<BigDecimal>
  3. কমানোর পদ্ধতিটি কল করুন।

    3.1। আমরা অতিরিক্ত হিসাবে একটি পরিচয় মান সরবরাহ BigDecimal.ZERO

    3.2। আমরা একটি পদ্ধতি রেফারেন্সের মাধ্যমে উল্লেখ করি BinaryOperator<BigDecimal>যা দুটি যোগ করে ।BigDecimalBigDecimal::add

সম্পাদনার পরে উত্তর আপডেট হয়েছে

আমি দেখতে পাচ্ছি যে আপনি নতুন ডেটা যুক্ত করেছেন, সুতরাং নতুন উত্তরটি হয়ে যাবে:

List<Invoice> invoiceList = new ArrayList<>();
//populate
Function<Invoice, BigDecimal> totalMapper = invoice -> invoice.getUnit_price().multiply(invoice.getQuantity());
BigDecimal result = invoiceList.stream()
        .map(totalMapper)
        .reduce(BigDecimal.ZERO, BigDecimal::add);

এটা বেশিরভাগ ছাড়া যে আমি একটি যোগ করেছি একই, totalMapperপরিবর্তনশীল, থেকে একটি ফাংশন আছে যা Invoiceথেকে BigDecimalএবং যে চালান মোট মূল্য ফেরৎ।

তারপরে আমি একটি পাই Stream<Invoice>, এটিকে ম্যাপ করব Stream<BigDecimal>এবং তারপরে এটিকে হ্রাস করব BigDecimal

এখন, একটি ওওপি নকশা বিন্দু থেকে আমি আপনাকে পরামর্শ দিচ্ছি total()যে আপনি ইতিমধ্যে যে পদ্ধতিটি ইতিমধ্যে সংজ্ঞায়িত করেছেন সেটিও ব্যবহার করুন , তবে এটি আরও সহজ হয়ে যায়:

List<Invoice> invoiceList = new ArrayList<>();
//populate
BigDecimal result = invoiceList.stream()
        .map(Invoice::total)
        .reduce(BigDecimal.ZERO, BigDecimal::add);

এখানে আমরা পদ্ধতিতে সরাসরি পদ্ধতি রেফারেন্স ব্যবহার করি map


12
Invoice::totalবনাম জন্য +1 invoice -> invoice.total()
ryvanage 25'14

12
পদ্ধতির রেফারেন্সের জন্য এবং স্ট্রিম ক্রিয়াকলাপগুলির মধ্যে লাইন ব্রেকগুলি যুক্ত করার জন্য +1, উভয়ই IMHO পাঠযোগ্যতার যথেষ্ট উন্নতি করে।
স্টুয়ার্ট

আমি কীভাবে চালান বলতে চাই: মোট এবং চালান :: একটি নতুন অ্যারেতে ট্যাক্স যুক্ত করতে চাইলে এটি কীভাবে কাজ করবে
রিচার্ড লাউ

জাভা স্ট্যান্ডার্ড লাইব্রেরিতে ইতিমধ্যে সংখ্যার সমষ্টি / ডাবলগুলির যোগফলের জন্য ফাংশন রয়েছে Collectors.summingInt()তবে সেগুলি তাদের জন্য মিস করে BigDecimal। লেখার পরিবর্তে reduce(blah blah blah)এটা পড়তে নিখোঁজ সংগ্রাহক লিখতে ভাল হবে কঠিন হয় BigDecimalএবং .collect(summingBigDecimal())আপনার পাইপলাইন শেষে।
csharpfolk

2
এই পদ্ধতির ফলে নালপোনটারে ধারণা
Gstackoverflow

11

এই পোস্টটিতে ইতিমধ্যে একটি পরীক্ষিত উত্তর রয়েছে, তবে উত্তরটি নাল মানগুলির জন্য ফিল্টার করে না। সঠিক উত্তরটি পূর্বাভাস হিসাবে অবজেক্ট :: নন নাল ফাংশনটি ব্যবহার করে নাল মানগুলি রোধ করা উচিত।

BigDecimal result = invoiceList.stream()
    .map(Invoice::total)
    .filter(Objects::nonNull)
    .filter(i -> (i.getUnit_price() != null) && (i.getQuantity != null))
    .reduce(BigDecimal.ZERO, BigDecimal::add);

এটি হ্রাস করার সাথে সাথে নাল মানগুলিকে যোগ করার চেষ্টা করতে বাধা দেয়।


7

আপনি পুনঃব্যবহারযোগ্য সংগ্রাহক হিসাবে নাম BigDecimalব্যবহার করে একটি স্ট্রিমের মানগুলি যোগ করতে পারেন : summingUp

BigDecimal sum = bigDecimalStream.collect(summingUp());

এটি Collectorএভাবে প্রয়োগ করা যেতে পারে:

public static Collector<BigDecimal, ?, BigDecimal> summingUp() {
    return Collectors.reducing(BigDecimal.ZERO, BigDecimal::add);
}

5

বিগডিসিমালের তালিকার যোগ করতে এই পদ্ধতির ব্যবহার করুন:

List<BigDecimal> values = ... // List of BigDecimal objects
BigDecimal sum = values.stream().reduce((x, y) -> x.add(y)).get();

এই পদ্ধতির প্রতিটি বিগডিসিমালকে কেবল একটি বিগডিসিমাল হিসাবে মানচিত্র করে এবং সংক্ষিপ্ত করে তাদের হ্রাস করে, যা পরে get()পদ্ধতিটি ব্যবহার করে ফিরে আসে ।

একই যোগফল করার জন্য আরও একটি সহজ উপায়:

List<BigDecimal> values = ... // List of BigDecimal objects
BigDecimal sum = values.stream().reduce(BigDecimal::add).get();

হালনাগাদ

আমি যদি সম্পাদিত প্রশ্নে ক্লাস এবং ল্যাম্বডা এক্সপ্রেশনটি লিখি তবে আমি এটি নিম্নরূপে লিখতাম:

import java.math.BigDecimal;
import java.util.LinkedList;

public class Demo
{
  public static void main(String[] args)
  {
    LinkedList<Invoice> invoices = new LinkedList<>();
    invoices.add(new Invoice("C1", "I-001", BigDecimal.valueOf(.1), BigDecimal.valueOf(10)));
    invoices.add(new Invoice("C2", "I-002", BigDecimal.valueOf(.7), BigDecimal.valueOf(13)));
    invoices.add(new Invoice("C3", "I-003", BigDecimal.valueOf(2.3), BigDecimal.valueOf(8)));
    invoices.add(new Invoice("C4", "I-004", BigDecimal.valueOf(1.2), BigDecimal.valueOf(7)));

    // Java 8 approach, using Method Reference for mapping purposes.
    invoices.stream().map(Invoice::total).forEach(System.out::println);
    System.out.println("Sum = " + invoices.stream().map(Invoice::total).reduce((x, y) -> x.add(y)).get());
  }

  // This is just my style of writing classes. Yours can differ.
  static class Invoice
  {
    private String company;
    private String number;
    private BigDecimal unitPrice;
    private BigDecimal quantity;

    public Invoice()
    {
      unitPrice = quantity = BigDecimal.ZERO;
    }

    public Invoice(String company, String number, BigDecimal unitPrice, BigDecimal quantity)
    {
      setCompany(company);
      setNumber(number);
      setUnitPrice(unitPrice);
      setQuantity(quantity);
    }

    public BigDecimal total()
    {
      return unitPrice.multiply(quantity);
    }

    public String getCompany()
    {
      return company;
    }

    public void setCompany(String company)
    {
      this.company = company;
    }

    public String getNumber()
    {
      return number;
    }

    public void setNumber(String number)
    {
      this.number = number;
    }

    public BigDecimal getUnitPrice()
    {
      return unitPrice;
    }

    public void setUnitPrice(BigDecimal unitPrice)
    {
      this.unitPrice = unitPrice;
    }

    public BigDecimal getQuantity()
    {
      return quantity;
    }

    public void setQuantity(BigDecimal quantity)
    {
      this.quantity = quantity;
    }
  }
}

.map(n -> n)সেখানে কি অকেজো? এছাড়াও get()প্রয়োজন হয় না।
রোহিত জৈন

@ রোহিতজাইন: আপডেট হয়েছে। ধন্যবাদ। এটি কল দ্বারা যেটি ফিরে get()আসে তার মান ফেরত দেওয়ার সাথে সাথে আমি ব্যবহার করেছি । যদি কেউ এর সাথে কাজ করতে চায় বা কেবল অঙ্কটি মুদ্রণ করে, তবে হ্যাঁ, প্রয়োজন হয় না। তবে printingচ্ছিক সরাসরি প্রিন্ট ভিত্তিক সিনট্যাক্স মুদ্রণ যা আমি সন্দেহ করি যে ব্যবহারকারীর প্রয়োজন হবে। এর থেকে মানটি পেতে একটি উপায়ে প্রয়োজন । OptionalreduceOptionalget()Optional[<Value>]get()Optional
আমান অগ্নিহোত্রি

@ রিওয়ান্টেজ: হ্যাঁ, আপনার পদ্ধতির ঠিক আমি কীভাবে এটি করতাম। :)
আমান অগ্নিহোহ্ত্রি

নিঃশর্ত getকল ব্যবহার করবেন না ! যদি valuesখালি তালিকা হয় তবে alচ্ছিকর কোনও মূল্য থাকবে না এবং NoSuchElementExceptionযখন getডাকা হবে তখন নিক্ষেপ করবে । values.stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO)পরিবর্তে আপনি ব্যবহার করতে পারেন ।
eee

4

আপনি যদি একটি তৃতীয় পক্ষের নির্ভরতা কিছু মনে না করেন, একটা শ্রেণী নামে হয় Collectors2 মধ্যে অন্ধকার সংগ্রহগুলি যা পদ্ধতি জন্য ফিরে সংগ্রাহক রয়েছে summing এবং সংক্ষেপিত BigDecimal এবং BigInteger। এই পদ্ধতিগুলি প্যারামিটার হিসাবে একটি ফাংশন নেয় যাতে আপনি কোনও বস্তু থেকে একটি বিগডিসিমাল বা বিগইন্টিজার মান বের করতে পারেন।

List<BigDecimal> list = mList(
        BigDecimal.valueOf(0.1),
        BigDecimal.valueOf(1.1),
        BigDecimal.valueOf(2.1),
        BigDecimal.valueOf(0.1));

BigDecimal sum =
        list.stream().collect(Collectors2.summingBigDecimal(e -> e));
Assert.assertEquals(BigDecimal.valueOf(3.4), sum);

BigDecimalSummaryStatistics statistics =
        list.stream().collect(Collectors2.summarizingBigDecimal(e -> e));
Assert.assertEquals(BigDecimal.valueOf(3.4), statistics.getSum());
Assert.assertEquals(BigDecimal.valueOf(0.1), statistics.getMin());
Assert.assertEquals(BigDecimal.valueOf(2.1), statistics.getMax());
Assert.assertEquals(BigDecimal.valueOf(0.85), statistics.getAverage());

দ্রষ্টব্য: আমি গ্রহগ্রাহ সংগ্রহের প্রতিশ্রুতিবদ্ধ।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.