0

我有一组代表产品尺寸的字符串,其中大多数在含义上重复但不是名称。(IE 大号尺寸至少有 14 种不同的拼写可能,每种拼写都需要保留。)我需要根据它们所代表的大小对它们进行排序。任何可能的小值都应该在任何可能的中值之前,等等。

我认为这是可能的唯一方法是实现一个特定的比较器,它包含不同的集合,将每个大小分组到它所代表的基本大小上。然后我可以通过确定特定大小属于哪个 Set 来实现 -1,0,1 关系。

有没有更强大的方法来实现这一点?具体来说,我担心从现在起两周后有人想出另一种拼写“大”的方法。

编辑:要清楚它不是我有疑问的实际比较器,它是包含每个组的集合的设置。这是处理这种情况的正常方法吗?我如何在未来证明它,以便每次添加新大小都不需要完全重新编译/部署?

4

3 回答 3

1

Custom comparator is the solution. I do not understand why do you worry that this is not robust enough.

于 2012-12-12T19:40:22.580 回答
1

一种简单的方法是从资源包中加载大小别名。一些示例代码(将所有文件放在同一个包中):

封装 size 属性的接口

public interface Sized {
    public String getSize();
}

一个产品类

public class Product implements Sized {

    private final String size;

    public Product(String size) {
        this.size = size;
    }

    public String getSize() {
        return size;
    }

    @Override
    public String toString() {
        return size;
    }
}

一个神奇的比较器:

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;

public class SizedComparator implements Comparator<Sized> {

    // maps size aliases to canonical sizes
    private static final Map<String, String> sizes = new HashMap<String, String>();

    static {
        // create the lookup map from a resourcebundle
        ResourceBundle sizesBundle = ResourceBundle
                .getBundle(SizedComparator.class.getName());
        for (String canonicalSize : sizesBundle.keySet()) {
            String[] aliases = sizesBundle.getString(canonicalSize).split(",");
            for (String alias : aliases) {
                sizes.put(alias, canonicalSize);
            }
        }
    }

    @Override
    public int compare(Sized s1, Sized s2) {
        int result;
        String c1 = getCanonicalSize(s1);
        String c2 = getCanonicalSize(s2);
        if (c1 == null && c2 == null) {
            result = 0;
        } else if (c1 == null) {
            result = -1;
        } else if (c2 == null) {
            result = 1;
        } else {
            result = c1.compareTo(c2);
        }
        return result;
    }

    private String getCanonicalSize(Sized s1) {
        String result = null;
        if (s1 != null && s1.getSize() != null) {
            result = sizes.get(s1.getSize());
        }
        return result;
    }

}

SizedComparator.properties:

1 = Small,tiny
2 = medium,Average
3 = Large,big,HUGE

单元测试(只是为了快乐的流程):

import org.junit.Before;
import org.junit.Test;

public class FieldSortTest {

    private static final String SMALL = "tiny";
    private static final String LARGE = "Large";
    private static final String MEDIUM = "medium";

    private Comparator<Sized> instance;

    @Before
    public void setup() {
        instance = new SizedComparator();
    }

    @Test
    public void testHappy() {
        List<Product> products = new ArrayList<Product>();
        products.add(new Product(MEDIUM));
        products.add(new Product(LARGE));
        products.add(new Product(SMALL));

        Collections.sort(products, instance);

        Assert.assertSame(SMALL, products.get(0).getSize());
        Assert.assertSame(MEDIUM, products.get(1).getSize());
        Assert.assertSame(LARGE, products.get(2).getSize());
    }
}

请注意,ResourceBundles 会自动缓存。您可以通过以下方式以编程方式重新加载 ResourceBundle:

ResourceBundle.clearCache();

(从 Java 1.6 开始)。或者,您可以使用一些Spring 魔法来创建自动重新加载消息资源。

如果从摇摇晃晃的属性文件中读取数据还不够酷,您也可以很容易地将您的大小别名保存在数据库中。

于 2012-12-12T23:26:30.443 回答
0

要对字符串集合(或一般的对象)强加任意顺序,执行此操作的标准方法是按照您的建议实现 Comparator 。

除了您建议的“手动”解决方案之外,您还可以考虑将字符串的相对编辑距离与规范示例进行比较。这将更加灵活,因为它将适用于您没有想到的替代方案。但就所涉及的工作而言,这对您的应用程序来说可能是多余的。

于 2012-12-12T20:02:32.347 回答