我有一个像这样的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值来计算平均值。
答案 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();
所涉及的步骤很简单:
通过将File
传递给Scanner
对象,可以将目标解析设置为File
而不是控制台。使用非常简洁的hasNextLine()
方法,您可以连续读取每一行,直到不再存在。然后用逗号分割每一行,并存储在String数组中以供参考。
由于您希望将整数累加在一起,因此您需要一种方法将已传入的字母与数字相关联。一个重量级但干净的方法是使用HashMap
。所需的Key
将是一个字符串,特别是A
B
或C
。通过利用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