find all elements in listA belonging to each element of listB and to sum according to listA

URL Link //n.sfs.tw/15360

2021-08-22 22:25:16 By

A bookseller has lots of books classified in 26 categories labeled A, B, ... Z.

For example an extract of one of the stocklists could be:

L = {"ABART 20", "CDXEF 50", "BKWRK 25", "BTSQZ 89", "DRTYM 60"}.

or

L = ["ABART 20", "CDXEF 50", "BKWRK 25", "BTSQZ 89", "DRTYM 60"]

You will be given a stocklist (e.g. : L) and a list of categories in capital letters e.g :

M = {"A", "B", "C", "W"}

or

M = ["A", "B", "C", "W"]

and your task is to find all the books of L with codes belonging to each category of M and to sum their quantity according to each category.

For the lists L and M of example you have to return the string (in Haskell/Clojure/Racket a list of pairs):

(A : 20) - (B : 114) - (C : 50) - (W : 0)

 

my solution according to: https://github.com/delacruzkb/CodeWars-Practice-Java.git

public class StockList { 	
  // 1st parameter is the stocklist (L in example), 
  // 2nd parameter is list of categories (M in example)
  public static String stockSummary(String[] lstOfArt, String[] lstOf1stLetter) 
  {
    String rtnval="";
    if(lstOfArt.length != 0 && lstOf1stLetter.length != 0)
    {
      //Process the summary based on the list of capital letters
      for(int i = 0; i < lstOf1stLetter.length; i++)
      {
        String currentLetter= lstOf1stLetter[i];
        int count =0;
      
        //loop through the list of art to find the matching book/stock
        for(int q = 0; q < lstOfArt.length; q++)
        {
          String currentArt = lstOfArt[q];
          if( currentArt.substring(0,1).equals(currentLetter) )
          {
            String[] artValues = currentArt.split(" ");
            count += Integer.parseInt(artValues[1]);
          }
        }
        //format the count of the book/stock
        String stock = "(" + currentLetter + " : " + count + ")";
        if(i != lstOf1stLetter.length - 1)
        {
          rtnval += stock + " - ";
        }
        else
        {
          rtnval += stock;
        }
      }
    }
    return rtnval;
  }
}

there are two best practices in my opinion using java.stream.collectors

1.

import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StockList {

    private static class Book {
        public final String category;
        public final String code;
        public final int quantity;

        public Book(String label) {
            category = label.substring(0,1);
            code = label.split(" ")[0].substring(1);
            quantity = Integer.parseInt(label.split(" ")[1]);
        }
    }

    public static String stockSummary(String[] lstOfArt, String[] lstOf1stLetter) {
        if (lstOfArt.length == 0 || lstOf1stLetter.length == 0)
          return "";
        Map<String, Integer> categoryCounts = Arrays.stream(lstOfArt)
                .map(Book::new)
                .collect(Collectors.groupingBy(book -> book.category,
                         Collectors.summingInt(book -> book.quantity)));
        return Arrays.stream(lstOf1stLetter)
                .map(initial -> String.format("(%s : %d)", 
                                              initial, categoryCounts.getOrDefault(initial, 0)))
                .collect(Collectors.joining(" - "));
    }
}

2.

import java.util.Map;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.summingInt;
import static java.util.stream.Collectors.joining;

public class StockList {
  private static int stockCount(final String s) {
    return Integer.valueOf(s.split(" ")[1]);
  }
  
  public static String stockSummary(final String[] stock, final String[] categories) {
    if (stock.length == 0 || categories.length ==  0)
      return "";
    final Map<String, Integer> counts = stream(stock)
        .collect(groupingBy(s -> s.substring(0, 1), summingInt(StockList::stockCount)));
    return stream(categories)
        .map(s -> "(" + s + " : " + counts.getOrDefault(s, 0) + ")")
        .collect(joining(" - "));
  }
}