1

对于我无法摆脱的情况,我需要一些示例代码的帮助。我有一个简单的对象列表。我的课是这样的:

class MyClass {
    String str;
    Integer intgr;
}

该列表包含以下元素:

[{a1  5}, {b2  3}, {g1  1}, {b5  1}, {c9  11}, {g2  3}, {d1  4}, {b3  19}... ... ...]

我需要检查是否有任何元素在字符串中包含相同的前缀(这里后缀是最后一个字符),然后保留具有更大整数值的元素。上述示例列表的预期输出将是:

[{a1  5}, {c9  11}, {g2  3}, {d1  4}, {b3  19}... ... ...]

字符串将具有唯一值,但可以在前缀中匹配。我在java中不是那么好。那么有人可以帮我解决这个问题吗?这是我正在尝试但得到的代码IndexOutOfBoundsException。这段代码有问题,所以需要你的帮助。

谢谢!

        int size = list.size();
        for (int j = 0; j < size; j++) {
        if (list.get(j).str.substring(0, list.get(j).str.length()-1).compareTo(list.get(j+1).str.substring(0, list.get(j+1).str.length()-1)) == 0) {
            if (list.get(j).intgr > list.get(j+1).intgr)
                list.remove(list.get(j+1));
                size--;
            else {
                list.remove(list.get(j));
                j--;
                size--;
            }
        }
    }
4

4 回答 4

1

您可以迭代您的元素集合,将它们添加到Map将键(前缀)与值(对象)关联起来。每次添加元素时,您都会检查以相同前缀存储的元素是否大于添加的元素。

为了有这种行为:

provides this: [{a1 5}, {b2 3}, {g1 1}, {b5 1}, {c9 11}, {g2 3}, {d1 4}, {b3 19}]
results this: [{a1 5}, {c9 11}, {g2 3}, {d1 4}, {b3 19}]

你可以实现这样的事情:

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class TestSystemOut {

    public static void main(final String[] a) {
        List<MyObj> list = prepareList();
        System.out.println("provides this: " + list);

        Map<String, MyObj> map = new LinkedHashMap<String, MyObj>(); // if result order doesn't matter this can be a simple HashMap

        String strTmp;
        for (MyObj obj : list) {

            strTmp = obj.str;
            strTmp = strTmp.substring(0, strTmp.length() - 1);

            if (map.get(strTmp) == null || map.get(strTmp).integer < obj.integer) {
                map.remove(strTmp); // this could be removed if order of result doesn't matter
                map.put(strTmp, obj);
            }
        }

        list.clear();
        list.addAll(map.values());

        System.out.println("results this: " + list);
    }

    public static class MyObj {
        String str;
        Integer integer;

        public MyObj(final String str, final Integer integer) {
            super();
            this.str = str;
            this.integer = integer;
        }

        @Override
        public String toString() {
            return "{" + str + " " + integer + "}";
        }

    }

    private static List<MyObj> prepareList() {
        List<MyObj> list = new ArrayList<MyObj>();
        list.add(new MyObj("a1", 5));
        list.add(new MyObj("b2", 3));
        list.add(new MyObj("g1", 1));
        list.add(new MyObj("b5", 1));
        list.add(new MyObj("c9", 11));
        list.add(new MyObj("g2", 3));
        list.add(new MyObj("d1", 4));
        list.add(new MyObj("b3", 19));
        return list;
    }
}
于 2012-06-27T18:44:30.107 回答
0

另一种(可能更容易阅读和调试)方法是:

  1. 将您的项目放入列表中
  2. 遍历列表并填充一个 Map,其中 String 是字母,MyClass 是最小值(即,如果地图已经包含“a”的内容,请检查您的新 MyClass 是更大或更小并相应地替换)

简单的实现:

public class Test {

    public static void main(String[] args) throws InterruptedException {
        List<MyClass> list = Arrays.asList(new MyClass("a1", 5),
                new MyClass("b2",  3),
                new MyClass("g1",  1),
                new MyClass("b5",  1),
                new MyClass("c9",  11),
                new MyClass("g2",  3),
                new MyClass("d1",  4),
                new MyClass("b3",  19));

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

        for (MyClass mc : list) {
            MyClass current = map.get(mc.getLetter());
            if (current == null || mc.intgr > current.intgr) {
                map.put(mc.getLetter(), mc);
            }
        }
        System.out.println(map);
    }

    static class MyClass  {

        String str;
        Integer intgr;

        MyClass(String str, Integer intgr) {
            this.str = str;
            this.intgr = intgr;
        }
        String getLetter() {
            return str.substring(0,1);
        }

        @Override
        public String toString() {
            return "[" + str + " " + intgr + "]";
        }
    }
}
于 2012-06-27T18:45:29.540 回答
0
/*
 * For every string in the list, look at all strings in the
 * list and compare the substring from 0 to length-1, if they
 * match and the id is not the same as the current s (i.e. s and
 * list.get(i) are at the same address) then remove that string.
 */
public ArrayList remdup(ArrayList<String> list) {

    for (String s : list) {
        for (int i=0; i<list.size();i++) {
            if (s.substring(0, s.length()-1).compareTo(list.get(i).substring(0, list.get(i).length()-1)) == 0
                    && list.indexOf(list.get(i)) != list.indexOf(s)) {
                list.remove(list.get(i));
            }
        }
    }
    return list;
}

也许试一试,尚未测试,但认为它应该可以工作。如果它不能尝试使用与 compareTo() 不同的东西,则可以使用 equals() 作为替代方法。

此外,您会收到 IndexOutOfBoundsException,因为每次删除元素时都会减去大小,从而使搜索区域变小。您没有考虑到 remove() 会为您执行此操作。

我会考虑为此使用 Map 而不是类。这样你就不必重新发明轮子了。

于 2012-06-27T19:01:49.637 回答
0

您的代码有两个问题。首先,当j == size - 1(最后一次迭代)时,您正在调用 list.get(j+1),这就是导致异常的原因。只需将循环条件更改为j < size - 1,异常就会消失。(或者,从前一个元素开始j = 1并与前一个元素进行比较。)

其次,您只是将每个元素与其直接后继元素进行比较。根据您的描述,这听起来不像您想要做的。

我建议在单独的方法中捕获比较逻辑。它可能是以下内容的一部分MyClass

class MyClass {
    String str;
    Integer intgr;
    /**
     * Returns the relationship between this and another MyClass instance.
     * The relationship can be one of three values:
     * <pre>
     *   -1 - This object should be discarded and other kept
     *    0 - There is no relationship between this and other
     *    1 - This object should be kept and other discarded
     * </pre>
     *
     * @param other The other instance to evaluate
     *
     * @return 0 if there is no relationship.
     */
    public int relationTo(MyClass other) {
        final String myPrefix = str.substring(0, str.length() - 1);
        final String otherPrefix = other.str.substring(0, other.str.length() - 1);
        if (myPrefix.equals(otherPrefix)) {
            return intgr < other.intgr ? -1 : 1;
        } else {
            return 0;
        }
    }
}

(这可以很容易地转换为具有两个参数的方法,该方法将在外部MyClass。)然后您可以使用该方法来决定要保留什么。您需要进行两次迭代才能找到不相邻的对象:

int size = list.size();
for (int i = 0; i < size; ++i) {
    final MyClass current = list.get(i);
    for (int j = 0; j < i; ++j) {
        final MyClass previous = list.get(j);
        final int relation = previous.relationTo(current);
        if (relation < 0) {
            // remove previous (at index j)
            list.remove(j);
            --i;
            --j;
            --size;
        } else if (relation > 0) {
            // remove current (at index i)
            list.remove(i);
            --i;
            --size;
            break; // exit inner loop
        }
        // else current and previous don't share a prefix
    }
}
于 2012-06-27T19:27:06.263 回答