write data from hashmap as a CSV file

倖福魔咒の 提交于 2021-01-27 13:25:23

问题


Say I have a hashmap with String type as key and ArrayList type as value, example {"value1"=["one","three","five"], "value2"=["two","four","six"]} where "value1" and "value2" are keys. I want to write the above hashmap data in following format. (so that I can read the csv file in excel)

value1,value2
one,two
three,four
five,six

My idea was to write the first key and its values as follows

value1
one
three
five

Then I was thinking of using the seek method in RandomAccessFile class to back to line 1 and again write the second key and its values. However I am not able to accomplish this task since seek function takes in the length of strings in the entire file and writes the new string after it. While I wanted the pointer to jump to the first line and append the string. Is there a better way to do this?. A quick example would be much appreciated.

Thanks


回答1:


Why can't you just use 4 Strings, one for each row? Something like this:

StringBuilder keyRow = new StringBuilder();
StringBuilder value1 = new StringBuilder();
StringBuilder value2 = new StringBuilder();
StringBuilder value3 = new StringBuilder();

Iterator keys = hashmap.keySet().iterator();
boolean notFirst = true;
while(keys.hasNext()) {
    String key = (String)keys.next();
    ArrayList list = (ArrayList)hashmap.get(key);
    if(!notFirst) {
        keyRow.append(",");
        value1.append(",");
        value2.append(",");
        value3.append(",");
    }
    keyRow.append(key);
    value1.append((String)list.get(0));
    value2.append((String)list.get(1));
    value3.append((String)list.get(2));
    notFirst = false;
}

Then at the end, just take the 4 Strings

String csv = keyRow.toString()+"\n"+value1.toString()+"\n"+value2.toString()+"\n"+value3.toString();

Note that this example isn't really proper CSV. Strings with commas aren't wrapped in quotes.


Or you iterate through the HashMap a thousand times if you have thousands of these rows. To save a bit of time from looking up a key, you can put them all in an ArrayList:

StringBuilder csv = new StringBuilder();
int row = 0;
ArrayList<ArrayList> list = new ArrayList<ArrayList>();

// Write the keys row:
Iterator keys = hashmap.keySet().iterator();
boolean notFirst = true;
while(keys.hasNext()) {
    String key = (String)keys.next();
    ArrayList tmp = (ArrayList)hashmap.get(key);
    if(!notFirst) {
        csv.append(",");
    }
    csv.append(key);
    // store list
    list.add(tmp);
    notFirst = false;
}
csv.append("\n");


// Write the rest of the rows
while(row<numberOfTotalRow) {
    notFirst = true;
    for(int x=0;x<list.size();x++) {
        if(!notFirst) {
            csv.append(",");
        }
        csv.append((String)list.get(x).get(row));
        notFirst = false;
    }   
    row++; 
}



回答2:


You can make a method that prints out the map as you wish:

public void toString(HashMap<String, ArrayList<String>> map) {
    for(int i = 0; i < map.size(); i++) {
        ArrayList<String> list = new ArrayList<String>(map.keySet());
        String key = list.get(i);
        System.out.println(key);
        for(int j = 0; j < map.get(key).size(); j++)
            System.out.println(map.get(key).get(j));
    }
}



回答3:


The way you have imagined is impossible. A file is a continuous stream of bytes. So after you write the first value, you have this in your file : "value1\none\nthree\nfive". If you then seek to position 6 (after "value") and insert new characters, you'll be overwiting the first value's second row. The following bytes won't be magically pushed away.

The only way to do this is to traverse the data you have in a way that allows you to output the bytes in the same order that they will be in the file. So: go to each value and write the first element, to each value again and write their second element and so on.




回答4:


You don't need a RandomAccessFile file, better use this:

HashMap<String, ArrayList<String>> map = new HashMap<>();
map.put("a", new ArrayList<>(Arrays.asList(new String[]{"A1", "A2", "A3"})));
map.put("b", new ArrayList<>(Arrays.asList(new String[]{"B1", "B2", "B3"})));
map.put("c", new ArrayList<>(Arrays.asList(new String[]{"C1", "C2", "C3"})));
{
    /**
        * Set your file printstream. For testing System.out
        */
    PrintStream ps = System.out;
    boolean first = true;
    /**
        * Size of the array list. Let's asume that the arraylist are of the
        * same lenght;
        */
    int s = 0;
    /**
        * Create a ArrayList variable because, this map class makes no guarantees
        * as to the order of the map; in particular, it does not guarantee that
        * the order will remain constant over time.
        */
    ArrayList<Entry<String, ArrayList<String>>> l =
            new ArrayList<>(map.entrySet());

    for (Entry<String, ArrayList<String>> e : l) {
        if (first) {
            first = false;
            s = e.getValue().size();
        } else {
            ps.print(",");
        }
        ps.print(e.getKey());
    }
    ps.println();

    for (int i = 0; i < s; i++) {
        first = true;
        for (Entry<String, ArrayList<String>> e : l) {
            if (first) {
                first = false;
            } else {
                ps.print(",");
            }
            ps.print(
                    e.getValue().get(i));
        }
        ps.println();
    }
}

Output:

b,c,a
B1,C1,A1
B2,C2,A2
B3,C3,A3


来源:https://stackoverflow.com/questions/11606376/write-data-from-hashmap-as-a-csv-file

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!