【问题标题】:write data from hashmap as a CSV file将 hashmap 中的数据写入 CSV 文件
【发布时间】:2012-07-23 04:08:15
【问题描述】:

假设我有一个以String 类型作为键和ArrayList 类型作为值的哈希图,例如{"value1"=["one","three","five"], "value2"=["two","four","six"]} 其中“value1”和“value2”是键。我想以以下格式编写上述哈希图数据。 (以便我可以在 excel 中读取 csv 文件)

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

我的想法是写第一个键和它的值如下

value1
one
three
five

然后我正在考虑使用 RandomAccessFile 类中的 seek 方法返回到第 1 行并再次写入第二个键及其值。但是,我无法完成此任务,因为 seek 函数会获取整个文件中字符串的长度并在其后写入新字符串。虽然我希望指针跳转到第一行并附加字符串。有一个更好的方法吗?。一个简单的例子将不胜感激。

谢谢

【问题讨论】:

    标签: java csv seek


    【解决方案1】:

    为什么不能只使用 4 个字符串,每行一个?像这样的:

    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;
    }
    

    最后,只取 4 个字符串

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

    请注意,此示例并不是真正正确的 CSV。带逗号的字符串不包含在引号中。


    或者,如果您有数千个这样的行,您将遍历 HashMap 一千次。为了节省查找密钥的时间,您可以将它们全部放在 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++; 
    }
    

    【讨论】:

    • 谢谢,但是我没有只有 4 行。这只是一个例子。我有大约一千行。
    • @Rkz 好吧,另一种选择是遍历 HashMap 大约一千次。
    【解决方案2】:

    您可以根据需要制作一个打印地图的方法:

    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】:

      你想象的方式是不可能的。文件是连续的字节流。因此,在您写入第一个值之后,您的文件中就有:“value1\none\nthree\nfive”。如果您随后寻找位置 6(在“值”之后)并插入新字符,您将覆盖第一个值的第二行。以下字节不会被神奇地推开。

      做到这一点的唯一方法是遍历您拥有的数据,使您能够以与它们在文件中相同的顺序输出字节。所以:转到每个值并写入第一个元素,再次到每个值并写入它们的第二个元素,依此类推。

      【讨论】:

        【解决方案4】:

        你不需要RandomAccessFile 文件,最好使用这个:

        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();
            }
        }
        

        输出:

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

        【讨论】:

          猜你喜欢
          • 2018-11-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-01-21
          • 1970-01-01
          • 1970-01-01
          • 2013-09-16
          相关资源
          最近更新 更多