如何在 java 中将 csv 转换为 multiMap?
How to convert csv to multiMap in java?
我正在处理如下一些数据,第一列是交易 ID,第二列是模拟 ID(重复很多),第三列是一些愚蠢的日期也很重复,第四列一个是交易的现值,大多数情况下它只是 0,但任何其他值都应该是非常独特的。
41120634|1554|20150203|-509057.56
40998001|1554|20150203|0
40960705|1554|20150203|0
40998049|1554|20150203|0
41038826|1554|20150203|0
41081136|1554|20150203|-7198152.23
41120653|1554|20150203|-319.436349
41081091|1554|20150203|-4.28520907E+009
我决定使用如下数据结构:
Map<Integer,Map<Integer,List<Map<Integer,Float>>>
然后我的 csv 将被保存为:
{20150203:{1554:[{41120634:-509057.56,41120634:0,...}]}}
我的问题是如何有效地将这样的 csv 文件转换为我想要的数据结构?
首先,在使用 CommonApache 的 CSV 方法后,创建一个适合您的数据的对象。
https://commons.apache.org/proper/commons-csv/
下面我找到了一段代码的摘录,我认为它对你有用。
public class csvToArray {
public ArrayList<data> csvTo_data() throws FileNotFoundException, IOException {
// Array to receive parser
ArrayList<data> your_data = new ArrayList<data>();
// data Object to receive the CSV data
data yourData = new data();
// call open file
OpenFile of = new OpenFile();
// get the files in a array of files
File[] files = of.chosefile();
// count number of files
int size = files.length;
for (int i = 0; i < size; i++) {
// CSV Parser can receive FileReader object, so I sent the path name
CSVParser parser = new CSVParser(new FileReader(files[i].getAbsolutePath()),
CSVFormat.DEFAULT.withSkipHeaderRecord());
System.out.println("You chose to open this file:" + files[i].getName());
// iterate to pass from CSV tyoe to Object data type
for (CSVRecord s : parser) {
String dataName = s.get(0);
String dataType = s.get(1);
int dataSize = Integer.parseInt(s.get(2));
// get the data from file's path name
int date = Integer.parseInt(files[i].getName().substring(3, 7));
yourData = new data(dataName , dataType , dataSize, date);
your_data.add(yourData);
}
parser.close();
}
return your_data;
像Map<K1, Map<K2, Map<K3, V>>>
这样的结构很容易实现。这种格式称为 NestedMap
,在本例中为 NestedMap3
,三个键和一个值。
使用继承很容易实现,因为 NestedMap3
在内部使用 Map<K1, NestedMap2<K2, K3, V>>
而 NestedMap2
使用 Map<K1, Map<K2, V>>
.
接下来你应该考虑在什么地方使用Map
以及在什么地方使用Pair<A, B>
、Triple<A, B, C>
等多容器
如果您的值经常更改,请使用像 Pair 这样的容器。如果您的值经常相同,请使用 Map
。基于此,您可以混合一些值,例如,如果后面的值经常更改,Map<K, Triple<A, B, C>>
可能会很好。
在您提供的场景中,第二个和第三个值通常相同。所以我建议在你的情况下使用 NestedMap3<Integer, Integer, Integer, Float>
。
首先是设置数据结构的代码,我假设您的输入是以 String
形式存储在 inputLines
:
中的行
NestedMap3<Integer, Integer, Integer, Float> map = new NestedMap3<>();
for (String line : inputLines) {
String[] values = inputLines.split("|");
map.put(toInt(values[0]), toInt(values[1]), toInt(values[2]), toFloat(values[3]));
}
当然我们还需要实现toInt
和toFloat
:
public Integer toInt(final String value) {
return Integer.parseInt(value);
}
public Float toFloat(final String value) {
return Float.parseFloat(value);
}
最后执行 NestedMap3
和 NestedMap2
:
public class NestedMap3<K1, K2, K3, V> {
private final Map<K1, NestedMap2<K2, K3, V>> mK1ToK2ToK3V =
new HashMap<K1, NestedMap2<K2, K3, V>>();
public V put(K1 key1, K2 key2, K3 key3, V value) {
NestedMap2<K2, K3, V> k2tok3toV = mK1ToK2ToK3V.get(key1);
if (k2tok3toV == null) {
k2tok3toV = new NestedMap2<>();
mK1ToK2ToK3V.put(key1, k2tok3toV);
}
return k2tok3toV.put(key2, key3, value);
}
public V get(K1 key1, K2 key2, K3 key3) {
final NestedMap2<K2, K3, V> k2tok3toV = mK1ToK2ToK3V.get(key1);
if (k2tok3toV == null) {
return null;
} else {
return k2tok3toV.get(key2, key3);
}
}
public Map<K3, V> get(K1 key1, K2 key2) {
final NestedMap2<K2, K3, V> k2toV = mK1ToK2ToK3V.get(key1);
if (k2toV == null) {
return null;
} else {
return k2toV.get(key2);
}
}
public NestedMap2<K2, K3, V> get(K1 key1) {
return mK1ToK2ToK3V.get(key1);
}
public Set<K1> keySet() {
return mK1ToK2ToK3V.keySet();
}
public void clear() {
mK1ToK2ToK3V.clear();
}
}
public class NestedMap2<K1, K2, V> {
private final Map<K1, Map<K2, V>> mK1ToK2ToV = new HashMap<K1, Map<K2, V>>();
public V put(K1 key1, K2 key2, V value) {
Map<K2, V> k2toV = mK1ToK2ToV.get(key1);
if (k2toV == null) {
k2toV = new HashMap<>();
mK1ToK2ToV.put(key1, k2toV);
}
return k2toV.put(key2, value);
}
public V get(K1 key1, K2 key2) {
final Map<K2, V> k2toV = mK1ToK2ToV.get(key1);
if (k2toV == null) {
return null;
} else {
return k2toV.get(key2);
}
}
public Map<K2,V> get(K1 key1) {
return mK1ToK2ToV.get(key1);
}
public Set<K1> keySet() {
return mK1ToK2ToV.keySet();
}
public Iterable<Pair<K1,K2>> keys2() {
return new Iterable<Pair<K1,K2>>() {
@Override
public Iterator<Pair<K1, K2>> iterator() {
return new Iterator<Pair<K1,K2>>() {
private Iterator<Entry<K1, Map<K2, V>>> mIterator1;
private Entry<K1, Map<K2, V>> mIterator1Object;
private Iterator<K2> mIterator2;
{
mIterator1 = mK1ToK2ToV.entrySet().iterator();
if (mIterator1.hasNext()) {
mIterator1Object = mIterator1.next();
mIterator2 = mIterator1Object.getValue().keySet().iterator();
}
}
@Override
public boolean hasNext() {
if (mIterator1Object == null) {
return false;
} else {
return mIterator2.hasNext();
}
}
@Override
public Pair<K1, K2> next() {
if (mIterator1Object == null) {
throw new NoSuchElementException();
} else {
if (!mIterator2.hasNext()) {
if (!mIterator1.hasNext()) {
throw new NoSuchElementException();
} else {
mIterator1Object = mIterator1.next();
assert mIterator1Object.getValue().size() > 0 : "must contain at least one value";
mIterator2 = mIterator1Object.getValue().keySet().iterator();
}
}
return new Pair<K1, K2>(mIterator1Object.getKey(), mIterator2.next());
}
}
};
}
};
}
public Iterable<Triple<K1,K2,V>> entrySet() {
final ArrayList<Triple<K1,K2,V>> result = new ArrayList<Triple<K1,K2,V>>();
for (final Entry<K1, Map<K2, V>> entryOuter : mK1ToK2ToV.entrySet()) {
for (final Entry<K2, V> entryInner : entryOuter.getValue().entrySet()) {
result.add(new Triple<>(entryOuter.getKey(), entryInner.getKey(), entryInner.getValue()));
}
}
return result;
}
public void addAll(NestedMap2<K1, K2, V> nestedMap) {
for (final Triple<K1, K2, V> triple : nestedMap.entrySet()) {
this.put(triple.getFirst(), triple.getSecond(), triple.getThird());
}
}
public Map<K2, V> remove(K1 k1) {
return mK1ToK2ToV.remove(k1);
}
public V remove(K1 k1, K2 k2) {
final Map<K2, V> k2ToV = mK1ToK2ToV.get(k1);
if (k2ToV == null) {
return null;
} else {
return k2ToV.remove(k2);
}
}
@Override
public String toString() {
return mK1ToK2ToV.toString();
}
public void clear() {
mK1ToK2ToV.clear();
}
}
我正在处理如下一些数据,第一列是交易 ID,第二列是模拟 ID(重复很多),第三列是一些愚蠢的日期也很重复,第四列一个是交易的现值,大多数情况下它只是 0,但任何其他值都应该是非常独特的。
41120634|1554|20150203|-509057.56
40998001|1554|20150203|0
40960705|1554|20150203|0
40998049|1554|20150203|0
41038826|1554|20150203|0
41081136|1554|20150203|-7198152.23
41120653|1554|20150203|-319.436349
41081091|1554|20150203|-4.28520907E+009
我决定使用如下数据结构:
Map<Integer,Map<Integer,List<Map<Integer,Float>>>
然后我的 csv 将被保存为:
{20150203:{1554:[{41120634:-509057.56,41120634:0,...}]}}
我的问题是如何有效地将这样的 csv 文件转换为我想要的数据结构?
首先,在使用 CommonApache 的 CSV 方法后,创建一个适合您的数据的对象。 https://commons.apache.org/proper/commons-csv/
下面我找到了一段代码的摘录,我认为它对你有用。
public class csvToArray {
public ArrayList<data> csvTo_data() throws FileNotFoundException, IOException {
// Array to receive parser
ArrayList<data> your_data = new ArrayList<data>();
// data Object to receive the CSV data
data yourData = new data();
// call open file
OpenFile of = new OpenFile();
// get the files in a array of files
File[] files = of.chosefile();
// count number of files
int size = files.length;
for (int i = 0; i < size; i++) {
// CSV Parser can receive FileReader object, so I sent the path name
CSVParser parser = new CSVParser(new FileReader(files[i].getAbsolutePath()),
CSVFormat.DEFAULT.withSkipHeaderRecord());
System.out.println("You chose to open this file:" + files[i].getName());
// iterate to pass from CSV tyoe to Object data type
for (CSVRecord s : parser) {
String dataName = s.get(0);
String dataType = s.get(1);
int dataSize = Integer.parseInt(s.get(2));
// get the data from file's path name
int date = Integer.parseInt(files[i].getName().substring(3, 7));
yourData = new data(dataName , dataType , dataSize, date);
your_data.add(yourData);
}
parser.close();
}
return your_data;
像Map<K1, Map<K2, Map<K3, V>>>
这样的结构很容易实现。这种格式称为 NestedMap
,在本例中为 NestedMap3
,三个键和一个值。
使用继承很容易实现,因为 NestedMap3
在内部使用 Map<K1, NestedMap2<K2, K3, V>>
而 NestedMap2
使用 Map<K1, Map<K2, V>>
.
接下来你应该考虑在什么地方使用Map
以及在什么地方使用Pair<A, B>
、Triple<A, B, C>
等多容器
如果您的值经常更改,请使用像 Pair 这样的容器。如果您的值经常相同,请使用 Map
。基于此,您可以混合一些值,例如,如果后面的值经常更改,Map<K, Triple<A, B, C>>
可能会很好。
在您提供的场景中,第二个和第三个值通常相同。所以我建议在你的情况下使用 NestedMap3<Integer, Integer, Integer, Float>
。
首先是设置数据结构的代码,我假设您的输入是以 String
形式存储在 inputLines
:
NestedMap3<Integer, Integer, Integer, Float> map = new NestedMap3<>();
for (String line : inputLines) {
String[] values = inputLines.split("|");
map.put(toInt(values[0]), toInt(values[1]), toInt(values[2]), toFloat(values[3]));
}
当然我们还需要实现toInt
和toFloat
:
public Integer toInt(final String value) {
return Integer.parseInt(value);
}
public Float toFloat(final String value) {
return Float.parseFloat(value);
}
最后执行 NestedMap3
和 NestedMap2
:
public class NestedMap3<K1, K2, K3, V> {
private final Map<K1, NestedMap2<K2, K3, V>> mK1ToK2ToK3V =
new HashMap<K1, NestedMap2<K2, K3, V>>();
public V put(K1 key1, K2 key2, K3 key3, V value) {
NestedMap2<K2, K3, V> k2tok3toV = mK1ToK2ToK3V.get(key1);
if (k2tok3toV == null) {
k2tok3toV = new NestedMap2<>();
mK1ToK2ToK3V.put(key1, k2tok3toV);
}
return k2tok3toV.put(key2, key3, value);
}
public V get(K1 key1, K2 key2, K3 key3) {
final NestedMap2<K2, K3, V> k2tok3toV = mK1ToK2ToK3V.get(key1);
if (k2tok3toV == null) {
return null;
} else {
return k2tok3toV.get(key2, key3);
}
}
public Map<K3, V> get(K1 key1, K2 key2) {
final NestedMap2<K2, K3, V> k2toV = mK1ToK2ToK3V.get(key1);
if (k2toV == null) {
return null;
} else {
return k2toV.get(key2);
}
}
public NestedMap2<K2, K3, V> get(K1 key1) {
return mK1ToK2ToK3V.get(key1);
}
public Set<K1> keySet() {
return mK1ToK2ToK3V.keySet();
}
public void clear() {
mK1ToK2ToK3V.clear();
}
}
public class NestedMap2<K1, K2, V> {
private final Map<K1, Map<K2, V>> mK1ToK2ToV = new HashMap<K1, Map<K2, V>>();
public V put(K1 key1, K2 key2, V value) {
Map<K2, V> k2toV = mK1ToK2ToV.get(key1);
if (k2toV == null) {
k2toV = new HashMap<>();
mK1ToK2ToV.put(key1, k2toV);
}
return k2toV.put(key2, value);
}
public V get(K1 key1, K2 key2) {
final Map<K2, V> k2toV = mK1ToK2ToV.get(key1);
if (k2toV == null) {
return null;
} else {
return k2toV.get(key2);
}
}
public Map<K2,V> get(K1 key1) {
return mK1ToK2ToV.get(key1);
}
public Set<K1> keySet() {
return mK1ToK2ToV.keySet();
}
public Iterable<Pair<K1,K2>> keys2() {
return new Iterable<Pair<K1,K2>>() {
@Override
public Iterator<Pair<K1, K2>> iterator() {
return new Iterator<Pair<K1,K2>>() {
private Iterator<Entry<K1, Map<K2, V>>> mIterator1;
private Entry<K1, Map<K2, V>> mIterator1Object;
private Iterator<K2> mIterator2;
{
mIterator1 = mK1ToK2ToV.entrySet().iterator();
if (mIterator1.hasNext()) {
mIterator1Object = mIterator1.next();
mIterator2 = mIterator1Object.getValue().keySet().iterator();
}
}
@Override
public boolean hasNext() {
if (mIterator1Object == null) {
return false;
} else {
return mIterator2.hasNext();
}
}
@Override
public Pair<K1, K2> next() {
if (mIterator1Object == null) {
throw new NoSuchElementException();
} else {
if (!mIterator2.hasNext()) {
if (!mIterator1.hasNext()) {
throw new NoSuchElementException();
} else {
mIterator1Object = mIterator1.next();
assert mIterator1Object.getValue().size() > 0 : "must contain at least one value";
mIterator2 = mIterator1Object.getValue().keySet().iterator();
}
}
return new Pair<K1, K2>(mIterator1Object.getKey(), mIterator2.next());
}
}
};
}
};
}
public Iterable<Triple<K1,K2,V>> entrySet() {
final ArrayList<Triple<K1,K2,V>> result = new ArrayList<Triple<K1,K2,V>>();
for (final Entry<K1, Map<K2, V>> entryOuter : mK1ToK2ToV.entrySet()) {
for (final Entry<K2, V> entryInner : entryOuter.getValue().entrySet()) {
result.add(new Triple<>(entryOuter.getKey(), entryInner.getKey(), entryInner.getValue()));
}
}
return result;
}
public void addAll(NestedMap2<K1, K2, V> nestedMap) {
for (final Triple<K1, K2, V> triple : nestedMap.entrySet()) {
this.put(triple.getFirst(), triple.getSecond(), triple.getThird());
}
}
public Map<K2, V> remove(K1 k1) {
return mK1ToK2ToV.remove(k1);
}
public V remove(K1 k1, K2 k2) {
final Map<K2, V> k2ToV = mK1ToK2ToV.get(k1);
if (k2ToV == null) {
return null;
} else {
return k2ToV.remove(k2);
}
}
@Override
public String toString() {
return mK1ToK2ToV.toString();
}
public void clear() {
mK1ToK2ToV.clear();
}
}