0

我有一个这样的 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();  
        }

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

4

4 回答 4

1

作为 C# 开发人员,有时很难不错过 linq 的功能。但正如 Farlan 建议的那样,您可以执行以下操作:

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);
    }
}
于 2013-03-17T21:52:46.670 回答
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]);
}
于 2013-03-17T19:58:16.000 回答
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 步 - 读取文件。

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

第 2 步 - 关联数据。

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

您现在需要做的就是打印出数据。随意采取不同的方法,但我希望这是一个清楚的例子,说明你如何在 Java 中做到这一点

于 2013-03-17T22:33:21.313 回答
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
于 2014-04-13T09:51:50.850 回答