【问题标题】:Java iteration for possible matches in ArrayListArrayList 中可能匹配项的 Java 迭代
【发布时间】:2014-01-29 15:04:43
【问题描述】:

我的问题是关于迭代和性能的。让我们考虑以下案例:

public class Car {

    private String name;
    private int type;
    private int horsePower;

    String getKey() {
        return type + "_" + horsePower;
    }

    private final int NUM_OF_CARS = 50000;

    public void test() {
        List<Car> cars = new ArrayList<Car>(NUM_OF_CARS);

        for (int i = 0; i < NUM_OF_CARS; i++) {
            Car c = new Car();

            if (i == 0 || i == 176 || i == 895 || i == 1500 || i == 4600) {
                c.name = "Audi A4 " + i;
                c.type = 1;
                c.horsePower = 200;
            } else {
                c.name = "Default";
                c.type = 2 + i;
                c.horsePower = 201;
            }

            cars.add(c);
        }

        // Matches should contain all Audi's since they have same type and horse
        // power

        long time = SystemClock.currentThreadTimeMillis();

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

        for (Car c : cars) {
            if (map.get(c.getKey()) != null) {
                map.get(c.getKey()).add(c);
            } else {
                List<Car> list = new ArrayList<Car>();
                list.add(c);
                map.put(c.getKey(), list);
            }
        }

        Iterator<Entry<String, List<Car>>> iterator = map.entrySet().iterator();

        while (iterator.hasNext()) {
            if (iterator.next().getValue().size() == 1) {
                iterator.remove();
            }
        }

        Log.d("test", String.valueOf((SystemClock.currentThreadTimeMillis() - time)));
    }
}

这是在这里找到所有奥迪的最有效方法吗?

这花了我 1700 毫秒

谢谢。

【问题讨论】:

  • 为什么嵌套 for 循环是一件坏事?您是否分析并确定这部分程序是一个瓶颈?
  • 集合应该是 ArrayList 还是其他一些可以接受的集合类/自定义集合?
  • 它可以是 ArrayList 以外的东西,只需要保存所有的 Cars。
  • 详细说明您的要求。你知道你想找到“奥迪” 1 型和 200 马力吗?然后你不需要循环内循环。或者你想找到所有类似的汽车?
  • 所有具有相同类型和马力的汽车,在更新的测试代码中,所有匹配奥迪的都有不同的名称并且代码有效,但我不知道它是否是最快的实现。

标签: java performance arraylist


【解决方案1】:

你为什么不试试(地图):

http://docs.oracle.com/javase/7/docs/api/java/util/Map.html

基本上它是 Hashmaps 的集合: http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html

这是一个例子:

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

【讨论】:

  • 比方说,匹配对象的名称可以不同,如奥迪A4、奥迪A4掀背车等,但由于类型和马力相同。
  • 我更想说HashMapMap类型
【解决方案2】:

这取决于为什么你要迭代。如果您确实需要访问每辆底层汽车,那么您真的别无选择。但是,如果您正在寻找与字符串的特定匹配项,那么您可能会考虑使用 Map。

【讨论】:

  • 示例中的匹配标准是类型和马力,在幸运的情况下,名称可以与匹配的对象相同,但可以不同,但​​对象仍然可以通过类似的测试
  • 我更新了我的问题,所以你不会有错误的想法,我可以使用带有车名键的地图。
  • 我的回答仍然是正确答案。如果您必须遍历整个列表,那么您真的别无选择。如果您担心查找时间并且可以事先进行一些索引,那么您应该使用地图。但是过早的优化是万恶之源,所以你可能担心一些无关紧要的事情。
【解决方案3】:

如果你想找到一个字符串,你应该使用 HashMap。否则,就我的想法而言,您无法避免这种类型的迭代。

【讨论】:

  • 问题是我不能在这里依赖名称,例如可以是宝马、奥迪和捷豹,但它们会与类型和马力相匹配。
【解决方案4】:

使用散列集合:使用 Object.hashCode() 和 Object.equals() 优化搜索的 HashSet。怎么样?

您必须定义 MyClass.hashCode() 和 equals() 的实现。 hashCode() 给出你的对象的整数表示(你可以在这里做你想做的事,但要让两个不同的对象有不同的值)

HashSet 然后将对您的结果进行模运算 例如:如果 HashSet 大小为 5000,它将模运算 5000,它会找到放置对象的索引 例如:如果您的 hashCode() 返回 10252,则 10252 % 5000 = 252。您的对象将被放入索引为 252 的数组中。

最后,当你问(我是否有一个“BMW x6”的实例时,你要求的对象将调用其 hashCode() 方法,该方法将再次返回 10252。并且 HashSet 只会搜索它是否有252 索引中的对象。

如果两个对象给出相同的 hashCode,那么它们将通过 equals() 方法进行比较。

我希望我的解释很清楚。简而言之,实现 hashCode 和 equals() 并尝试优化 hashCode() 的实现,以便在填充 HashSet 时获得时间

您可能还会对 HashMap 感兴趣,它存储键和值,其中键使用散列机制:因此您可以通过键找到对象

【讨论】:

  • 你说的是“HashSet”吗?如果您使用任何“设置”,它将丢弃所有重复项!在这种情况下,集合将只有一个类型和马力的对象。在那之后就没有什么可计算的了!
  • 您的对象负责提供自己的 hashCode() 方法:因此您可以决定是否将具有不同选项的两辆车视为相同:您可以在 hashCode() 方法中包含对您很重要的字段:如果差异依赖于 Car(型号、功率、颜色、版本),只需将这些值组合起来计算您的 hashCode 和 equals 方法(RaviH,您了解 Set 的工作原理吗?您的问题很奇怪)
猜你喜欢
  • 2015-12-21
  • 1970-01-01
  • 2011-12-31
  • 2015-09-29
  • 2020-05-09
  • 1970-01-01
  • 2011-09-11
  • 2019-09-09
  • 2013-01-17
相关资源
最近更新 更多