Java哈希映射/数组列表计算不同的值

时间:2017-12-31 11:37:41

标签: java csv arraylist count hashmap

我对编程非常陌生,而且我有一个任务要做,但是我被卡住了。

我必须实施一个程序,该程序将读取CSV文件(100万行+行)并计算在特定日期订购“x”个不同产品的客户数量。

CSV如下所示:

Product Name | Product ID | Client ID |  Date
Name              544           86       10/12/2017
Name              545           86       10/12/2017
Name              644           87       10/12/2017
Name              644           87       10/12/2017
Name              9857          801      10/12/2017
Name              3022          801      10/12/2017
Name              3021          801      10/12/2017

我的代码的结果是:

  

801:2 - 不正确

     

86:2 - 正确

     

87:2 - 不正确

所需的输出是:

  

客户1(801):3种不同的产品

     

客户2(86):2种不同的产品

     

客户3(87):1个不同的产品

另外,

  • 如果我想知道有多少客户订购了2种不同的产品,我希望结果如下:

总计:1位客户订购了2种不同的产品

  • 如果我想知道一天内订购的不同产品的最大数量,我希望结果如下:

订购的不同产品的最大数量为:3

我尝试使用Google Guava的Hash Map和Multimap(我最好的猜测),但我无法绕过它。

我的代码如下所示:

package Test;

import java.io.BufferedReader;
import java.io.FileReader;    
import java.io.IOException;

import java.util.ArrayList;   
import java.util.HashMap;    
import java.util.Map;  

import com.google.common.collect.ArrayListMultimap;  
import com.google.common.collect.HashMultimap;    

public class Test {

    public static void main(String[] args) {
        //HashMultimap<String, String> myMultimap = HashMultimap.create();
        Map<String, MutableInteger> map = new HashMap<String, MutableInteger>();
        ArrayList<String> linesList = new ArrayList<>();
        // Input of file which needs to be parsed
        String csvFile = "file.csv";
        BufferedReader csvReader;

        // Data split by 'TAB' in CSV file
        String csvSplitBy = "\t";
        try {
            // Read the CSV file into an ArrayList array for easy processing.
            String line;
            csvReader = new BufferedReader(new FileReader(csvFile));
            while ((line = csvReader.readLine()) !=null) {
                linesList.add(line);
            }
            csvReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        } 

        // Process each CSV file line which is now contained within
        // the linesList list Array
        for (int i = 0; i < linesList.size(); i++) {
            String[] data = linesList.get(i).split(csvSplitBy);
            String col2 = data[1];
            String col3 = data[2];
            String col4 = data[3];

            // Determine if Column 4 has the desired date
            // and count the values
            if (col4.contains("10/12/2017"))  {
                String key = col3;
                if (map.containsKey(key)) {
                      MutableInteger count = map.get(key);
                      count.set(count.get() + 1);
                } else {
                      map.put(key, new MutableInteger(1));
                }
            }
        }

        for (final String k : map.keySet()) {
            if (map.get(k).get() == 2) {
              System.out.println(k + ": " + map.get(k).get());
            }
        }
    }
}

非常感谢任何关于如何实施这一建议的建议或建议。

先谢谢你们。

1 个答案:

答案 0 :(得分:1)

您可以按Set存储productIds clientId,并且只需要大小Set。 由于productIds不允许重复值,因此这将有效地为您提供Map<String, Set<String>> distinctProductsPerClient = new HashMap<String, Set<String>>(); // Process each CSV file line which is now contained within // the linesList list Array // Start from 1 to skip the first line for (int i = 1; i < linesList.size(); i++) { String line = linesList.get(i); String[] data = line.split(csvSplitBy); String productId = data[1]; String clientId = data[2]; String date = data[3]; // Determine if Column 4 has the desired date // and count the values if (date.contains("10/12/2017")) { if (!distinctProductsPerClient.containsKey(clientId)) { distinctProductsPerClient.put(clientId, new HashSet<>()); } distinctProductsPerClient.get(clientId).add(productId); } } for (final String clientId : distinctProductsPerClient.keySet()) { System.out.println(clientId + ": " + distinctProductsPerClient.get(clientId).size()); } 的不同数量。

此外,我建议您为变量提供有意义的名称,而不是col2,k,map ...这将使您的代码更具可读性。

OrderData

使用Stream API的更高级解决方案(需要Java 9)

如果您引入课程private static class OrderData { private final String productName; private final String productId; private final String clientId; private final String date; public OrderData(String csvLine) { String[] data = csvLine.split("\t"); this.productName = data[0]; this.productId = data[1]; this.clientId = data[2]; this.date = data[3]; } public String getProductName() { return productName; } public String getProductId() { return productId; } public String getClientId() { return clientId; } public String getDate() { return date; } } (代表CSV中的一行),请执行以下操作:

Map<String, Set<String>> distinctProductsPerClient2 = linesList.stream()
        .skip(1)
        .map(OrderData::new)
        .collect(groupingBy(OrderData::getClientId, mapping(OrderData::getProductId, toSet())));

你可以用这个替换for循环:

v[1][1].x=0;

但是我认为如果你是新手编程的话,这可能会有点复杂(尽管如果你试图理解上面代码的作用,这可能是一个很好的练习。)