使用Java从集合中提取数据

时间:2013-03-17 19:52:15

标签: java linq csv

我有一个像这样的csv数据集:

A, 10, USA
B,30, UK
C,4,IT
A,20,UK
B,10,USA

我想阅读这些csv行并提供以下输出:

A has ran 30 miles with average of 15. 
B has ran 30 miles with average of 20.
C has ran 4 miles with average of 4. 

我想用Java实现这一目标。我在C#中使用Linq:

完成了这个
var readlines = File.ReadAllLines(filename);
            var query = from lines in readlines
                        let data = lines.Split(',')
                        select new
                        {
                            Name = data[0],
                            Miles = data[1],

                        };

            var values = query.GroupBy(x => new {x.Name}).Select(group => new { Person = group.Key, Events = group.Sum(g =>Convert.ToDouble(g.Miles)) ,Count = group.Count() });

我希望用Java做到这一点,我不确定如果不使用任何第三方库我是否可以这样做?有任何想法吗? 到目前为止,我的代码在Java中看起来像这样:

CSVReader reader = new CSVReader(new FileReader(filename));
        java.util.List<String[]> content = reader.readAll();
        String[] row = null;
        for(Object object:content)
        {
          row = (String[]) object;
          String Name = row[0];
          String Miles = row[1];



          System.out.printf("%s has ran %s miles %n",Name,Miles);
        }

           reader.close();  
        }

我正在寻找一种很好的方法来获取每个名称的总milage值来计算平均值。

4 个答案:

答案 0 :(得分:1)

作为C#开发人员,有时候很难错过linq的功能。但正如法兰建议你可以这样做:

CSVReader reader = new CSVReader(new FileReader(filename));
    java.util.List<String[]> content = reader.readAll();
    Map<String, Group> groups = new HashMap<>();
    for(String[] row : content)
    {
        String Name = row[0];
        String Miles = row[1];

        System.out.printf("%s has ran %s miles %n", Name, Miles);

        if (groups.containsKey(Name)){
            groups.get(Name).Add(Double.valueOf(Miles));
        } else {
            Group g = new Group();
            g.Add(Double.valueOf(Miles));
            groups.put(Name, g);
        }
    }
    reader.close();

    for (String name : groups.keySet())
    {
        System.out.println(name + " ran " + groups.get(name).total() + " with avg of " + groups.get(name).average());
    }


}

class Group {
    private List<Double> miles;

    public Group()
    {
        miles = new ArrayList<>();
    }

    public Double total(){
        double sum = 0;
        for (Double mile : miles)
        {
            sum += mile;
        }
        return sum;
    }

    public Double average(){
        if (miles.size() == 0)
            return 0d;            
        return total() / miles.size();
    }

    public void Add(Double m){
        miles.add(m);
    }
}

答案 1 :(得分:0)

使用Java的BufferedReader类:

BufferedReader in = new BufferedReader(new FileReader("your.csv"));
String line;
while ( (line = in.readLine()) != null) {
  String [] fields = line.split(",");
  System.out.println(fields[0] + " has ran " + fields[1] + " miles with average " + fields[2]);
}

答案 2 :(得分:0)

有很多方法可以做到这一点,一些冗长的方法,一些更短。问题是Java在执行简单任务时可能非常冗长,因此更好的方法可能会更加丑陋。

以下示例显示了如何实现此目标,与打印相同。但请记住,它可能不是最好的方法,但我觉得更容易阅读和理解。

    final File csvFile = new File("filename.csv");
    final Scanner reader = new Scanner(csvFile);

    final Map<String, Integer> info = new HashMap<>(); //Store the data

    //Until there is are no more lines, continue
    while (reader.hasNextLine()) {
        final String[] data = reader.nextLine().split(","); // data[0] = A. [1] = 10. [2] = USA
        final String alpha = data[0];

        if (!info.containsKey(alpha)) {
            info.put(alpha, Integer.parseInt(data[1]));
        } else {
            int miles = info.get(alpha);
            info.put(alpha, miles + Integer.parseInt(data[1]));
        }
    }

    reader.close();

所涉及的步骤很简单:

第1步 - 阅读文件。

通过将File传递给Scanner对象,可以将目标解析设置为File而不是控制台。使用非常简洁的hasNextLine()方法,您可以连续读取每一行,直到不再存在。然后用逗号分割每一行,并存储在String数组中以供参考。

第2步 - 关联数据。

由于您希望将整数累加在一起,因此您需要一种方法将已传入的字母与数字相关联。一个重量级但干净的方法是使用HashMap。所需的Key将是一个字符串,特别是A BC。通过利用Key唯一的事实,我们可以使用O(1) containsKey(String)方法检查我们是否已经阅读了这封信。如果是新的,请将其添加到HashMap并使用它保存数字。 如果但是,之前已经看到过该字母,我们找到旧值,将其添加到新值并覆盖HashMap内的数据。

您现在需要做的就是打印出数据。随意采取不同的方法,但我希望这是一个明确的例子,说明你 CAN 如何用Java做这件事。

答案 3 :(得分:0)

也许您可以尝试这个Java库:https://code.google.com/p/qood/

它处理没有任何getter / setter的数据,因此它比LINQ更灵活。

在您的情况下,文件“D:/input.csv”有3列:

NAME,MILES,COUNTRY
A, 10, USA
B,30, UK
C,4,IT
A,20,UK
B,10,USA

查询代码为:

final QModel raw = QNew.modelCSV("D:/input.csv")
  .debug(-1);//print out what read from CSV
raw.query()
  .selectAs("OUTPUT", 
    "CONCAT(NAME,' has ran ',SUM(MILES),' miles with average of ',MEAN(MILES),'.')")
  .groupBy("NAME")
  .result().debug(-1)//print out the result
  .to().fileCSV("D:/output.csv", "UTF-8");//write to another CSV file