从字符串数组java中获取2个元素的所有组合

时间:2017-05-27 16:27:01

标签: java arrays algorithm hash hashmap

假设我有这个数组列表['a','b','xx']。 我想提取每2个字符串组合(每2个元素)。例如['a','b'] ['a','xx'] ['b','a'] ['b','xx'] ['xx','a'] ['xx ','b']。

我已经编写了这段代码,但是当数组变得非常大时(10k for 例如,GC耗尽内存。

        private Text empty = new Text("");

    public void start(Iterable<Text> values,Context context) throws {
        List<String> sitesArr = new ArrayList<String>();
        HashMap<String, String> hmapPairs = new HashMap<String, String>();

        for (Text site : values){
            sitesArr.add(site.toString());
        }

        insertPairsToHash(hmapPairs, sitesArr);
        writeContextFromHash(hmapPairs, context);
    } 

    private void insertPairsToHash(HashMap<String, String> hmapPairs, List<String> sitesArr) {
        for (int i=0; i<sitesArr.size(); i++) {
            for (int j=i+1; j<sitesArr.size(); j++) {
                String firstPair = sitesArr.get(i) + "_" + sitesArr.get(j);
                String secondPair = sitesArr.get(j) + "_" + sitesArr.get(i);
                hmapPairs.put(firstPair,secondPair);
            }      
        }
    }

    private void writeContextFromHash(HashMap<String, String> hmapPairs, Context context) throws IOException, InterruptedException {
        Text textTowriteToFile = new Text("");
        for(Map.Entry<String, String> entry : hmapPairs.entrySet()) {
            textTowriteToFile.set(entry.getKey());
            context.write(textTowriteToFile, empty);
            textTowriteToFile.set(entry.getValue());
            context.write(textTowriteToFile, empty);
        }
    }

我使用2 for循环,在每次迭代中我插入2个组合(['a','b']和['b','a']第一个元素是键,第二个是值,所以在[哈希表示'a','b']'a'将是键,'b'将是值,反之亦然)。 然后我在哈希上迭代一次以发送值。 如何在使用更少内存的同时加快速度?

3 个答案:

答案 0 :(得分:0)

为什么不直接在嵌套的for循环中调用“writeContextFromHash”而不创建HashMap?

答案 1 :(得分:0)

您应该在问题中添加更多信息。但基本上使用这种程序,随着输入变大,你总会遇到内存问题。使用10k条目,您最终会得到大约100米的组合,从而产生50米的地图条目。与数据结构的大小相乘(取决于您的输入),这会占用大量内存。 如果你事先知道输入的粗略大小,你可能只需为你的jvm分配足够的内存(除非你的机器很小)。如果这不能解决问题,则无法将所有结果保留在内存中。换出磁盘或按照上面的建议将结果直接写入控制台,而不是将它们保存在内存中。

答案 2 :(得分:0)

您可以简单地重构您的课程流式搜索结果。所以你不要保留组合元素的整个结果列表。

    private Text empty = new Text("");

   public void start(Iterable<Text> values,Context context) throws IOException, InterruptedException  {
       List<String> sitesArr = new ArrayList<String>();

       for (Text site : values){
           sitesArr.add(site.toString());
       }
       insertPairsToHash(sitesArr,context);
   } 

   private void insertPairsToHash(List<String> sitesArr, Context context) {
       for (int i=0; i<sitesArr.size(); i++) {
           for (int j=i+1; j<sitesArr.size(); j++) {
               String firstPair = sitesArr.get(i) + "_" + sitesArr.get(j);
               String secondPair = sitesArr.get(j) + "_" + sitesArr.get(i);

               doWrite(context, firstPair, secondPair);
           }      
       }
   }

    private void doWrite(Context context, String firstPair, String secondPair) {
        Text textTowriteToFile = new Text("");
           textTowriteToFile.set(firstPair);
           context.write(textTowriteToFile, empty);
           textTowriteToFile.set(secondPair);
           context.write(textTowriteToFile, empty);
    }

这会降低你的内存使用量。

一般情况下,如果您的输入很大或没有限制,您会尝试流式传输结果,流式传输会增加一些复杂性,但会使内存使用量与您输入的大小无关。

编辑(评论后):

您可以通过从列表中删除已删除的元素来删除它们。 在这种情况下,您应该使用LinkedList而不是ArrayList,因为从数组列表中删除head元素将涉及更多的GC和CPU时间,而不是链接列表中的相同操作。

然而,这不会降低峰值内存使用量,只会降低使用时间(随着进程的进行,您将需要更少的内存)。

如果其他组件在进程过程中消耗更多内存,它仍然可能有用。

 List<String> sitesArr = new LinkedList<>();

private void insertPairsToHash(List<String> sitesArr, Context context) {
    while (!sitesArr.isEmpty()) {
        String left = sitesArr.remove(0);
        for (String right : sitesArr) {
            String firstPair = left + "_" + right;
            String secondPair = right + "_" + left;
            doWrite(context, firstPair, secondPair);
        }
    }
}