如何在java中使用相同的键找到多个记录中的最小值?

时间:2015-07-29 06:22:55

标签: java algorithm data-structures

我从文件中收集了一些记录,并希望在类似于SQL的记录上执行group by和minimum。记录采用键值对的形式,其中值不是浮点值或双值,如: 这里的值是版本号,就像每个软件都有基于以下版本的版本号:10.1.1,10.1.2,10.1.3等

 A 1.12
 A 1.13
 A 1.45
 B 5.6
 B 4.5
 C 5.6.4

 Output should be ->  A 1.12
                      B 4.5
                      C 5.6.4

最初我开始使用HashMap数据结构来解决这个问题:

Map<String,List<String>> map = new HashMap<>();

由于值不是float或double,我遍历所有值并删除小数点和连接数字以形成整数。

例如:A 112 A 113

我遇到了问题,如何找到具有最小值的密钥?我试图使用TreeMap但没有运气。

任何人都可以帮我找到具有最小价值的密钥吗?

输出应为:A 1.12 B 4.5 C 5.6.4

对于像Eg:C 5.6.4这样的单个记录,最小值是单个记录。

根据我的数据结构选择Map<String,List<Integer>>,我遇到的问题是如何找到具有最小值的键,就像我们在SQL查询中一样,使用group by和min聚合函数。 ,这里我得到了A - &gt; [] A - &gt; [] A - &gt; [] B - &gt; [] B - &gt; [] C - &gt; [] **这里的挑战是在同一个密钥**的多个列表中找到最小值,正如您可以看到的,基于我的数据结构选择,同一个密钥有多个列表。

4 个答案:

答案 0 :(得分:1)

第一个挑战是找到&#34; minimal&#34;值。简单地删除句点并将值视为整数是不够的 - 这将导致6.5.4.更小&#34;更小&#34;比1.2.3.4.,似乎不是你想要的。更好的方法是按周期划分字符串,并将每个元素分别视为int

public String min(String v1, String v2) {
    // Any string should be "smaller" than null
    if (v1 == null) {
        return v2;
    }
    if (v2 == null) {
        return v1;
    }

    // Split both of them and iterate the common indexes:
    String[] v1parts = v1.split("\\.");
    String[] v2parts = v2.split("\\.");
    int commonLenth = Math.min(v1parts.length, v2parts.length);
    for (int i = 0; i < commonLength; ++i) {
        int v1elem = Integer.parseInt(v1parts[i]);
        int v2elem = Integer.parseInt(v2parts[i]); 
        if (v1elem < v2elem) {
            return v1;
        } else if (v1elem > v2elem) {
            return v2;
        }
    }

    // Done iterating the common indexes and they are all equal
    // The shorter string is therefore the minimal one:
    if (v1parts.length < v2parts.length) {
        return v1;
    } 
    return v2;
}

既然你有这样的功能,那只需要迭代键值对并将最小值放在Map中。例如。 (伪代码假设你有某种Pair类):

Map<String, String> minimums = new HashMap<>();
for (Pair<String, String> entry : myListOfPairs) {
      String key = entry.getKey();
      minimums.put(key, min(entry.getValue(), minimums.get(key));
}

答案 1 :(得分:1)

请找到以下解决方案:

您可以使用&#34; key&#34;维护HashMap。作为字符串和&#34;值&#34;为PriorityQueue

HashMap<String,PriorityQueue<String>> map = new HashMap<String,PriorityQueue<String>>();

您可以按键对值进行分组,并可以保留PriorityQueue中的值。

爪哇 &#39; s PriorityQueue是一个Min Heap,其最小值存储在根目录中。 当你在priorityQueue上调用peek()方法时,它将返回存储在根目录下的最小值。

以下是可以帮助您的示例代码:

import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.PriorityQueue;
public class GroupAndFindMinimum {

    public static void main(String[] args) {

        HashMap<String,PriorityQueue<String>> map = new HashMap<String,PriorityQueue<String>>();

        PriorityQueue<String> q1 = new PriorityQueue<String>();
        q1.add("1.12");q1.add("1.13");q1.add("1.45");

        PriorityQueue<String> q2 = new PriorityQueue<String>();
        q2.add("5.6");q2.add("4.5");

        PriorityQueue<String> q3 = new PriorityQueue<String>();
        q3.add("5.6.4");

        map.put("A",q1);
        map.put("B", q2);
        map.put("C", q3);


        for(Iterator<? extends Map.Entry<? extends String, ? extends PriorityQueue<String>>> it = map.entrySet().iterator(); it.hasNext() ;)
        {
            Map.Entry<? extends String, ? extends PriorityQueue<String>> t = it.next();
            System.out.println(t.getKey() + " " + t.getValue().peek());
        }

    }

}

以下是上述程序的输出:

A 1.12
B 4.5
C 5.6.4

如果您需要为每个组返回 MAX值,那么您可以借助&#34; 比较器&#34;来实现它。同样。

以下是代码:

import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.PriorityQueue;
public class GroupAndFindMinimum {

    public static void main(String[] args) {

        HashMap<String,PriorityQueue<String>> map = new HashMap<String,PriorityQueue<String>>();
        comparatorPQ comp = new comparatorPQ<String>();

        PriorityQueue<String> q1 = new PriorityQueue<String>(3,comp);
        q1.add("1.12");q1.add("1.13");q1.add("1.45");

        PriorityQueue<String> q2 = new PriorityQueue<String>(2,comp);
        q2.add("5.6");q2.add("4.5");

        PriorityQueue<String> q3 = new PriorityQueue<String>(1,comp);
        q3.add("5.6.4");

        map.put("A",q1);
        map.put("B", q2);
        map.put("C", q3);


        for(Iterator<? extends Map.Entry<? extends String, ? extends PriorityQueue<String>>> it = map.entrySet().iterator(); it.hasNext() ;)
        {
            Map.Entry<? extends String, ? extends PriorityQueue<String>> t = it.next();
            System.out.println(t.getKey() + " " + t.getValue().peek());
        }

    }

}

class comparatorPQ<k> implements Comparator
{

    @Override
    public int compare(Object a1, Object b1) {
        String a = null ,b= null;

        if(a1 instanceof String)
         a = (String)a1;

        if(b1 instanceof String)
        b = (String)b1;


        if( b.compareTo(a) > 1 )
            return 1;
        else if(b.compareTo(a) < 1)
            return -1;
        return 0;
    }

}

输出:

A 1.45
B 5.6
C 5.6.4

答案 2 :(得分:0)

O(n)算法解析输入一次并继续更新输出映射就足够了。我假设输入是以两个相同大小的列表的形式提供的。

public Map<String, String> groupAndFindMinimum(ArrayList< String > inputKeys, ArrayList< String > inputValues){
    Map<String, String> output = new ArrayMap<String, String>();
    int i = 0;
    for(String key : inputKeys){
        if(output.containsKey(key)){
            output[key] = min(output[key], inputValues.get(i));
        }
        else{
            output.insert(key, inputValues.get(i));
        }
        i++;
    }
    return output;
}

我希望这会有所帮助。 找到最小值的算法是正确的。

答案 3 :(得分:-1)

据我所知,问题中没有与性能相关的问题。

我建议你直截了当地思考。

     A 1.12
     A 1.13
     A 1.45
     B 5.6
     B 4.5
     C 5.6.4

按键对所有元素进行分组

     A [1.12, 1.13, 1.45]
     B [5.6, 4.5]
     C [5.6.4]

然后通过使用您自己的排序算法迭代所有列表来查找每个数组的最小值,因为这些项目不是数字。

     A [1.12]
     B [4.5]
     C [5.6.4]

你知道,这既不复杂也不困难。

现在你可以想到有什么可以改进的。