我有一堆类Puzzle
的对象。我已覆盖equals()
和hashCode()
。当需要向用户提供解决方案时,我想过滤掉所有“相似”的拼图(按照我定义的标准),因此用户只能看到其中一个。
相似性是可传递的。
示例:
Result of computations:
A (similar to A)
B (similar to C)
C
D
在这种情况下,只会向用户呈现A或D和B或C,但不会出现两个类似的谜题。两个相似的谜题同样有效。重要的是它们不会向用户显示。
为实现这一目标,我想使用禁止重复的ADT。但是,我不想更改equals()
和hashCode()
方法来返回关于相似性的值。在这种情况下,我可以使用Equalator
之类的Comparator
吗?或者我应该采取另一种方式吗?
我正在上课的是一个维护字母网格的拼图。 (与拼字游戏一样。)如果拼图包含相同的单词,但其方向不同,则认为它是相似的。以下是谜题:
(2, 2): A
(2, 1): C
(2, 0): T
类似于:
(1, 2): A
(1, 1): C
(1, 0): T
答案 0 :(得分:2)
我使用的包装类会相应地覆盖equals
和hashCode
。
private static class Wrapper {
public static final Puzzle puzzle;
public Wrapper(Puzzle puzzle) {
this.puzzle = puzzle;
}
@Override
public boolean equals(Object object) {
// ...
}
@Override
public int hashCode() {
// ...
}
}
然后你把所有的谜题都包起来,把它们放在地图上,再把它们拿出来......
public Collection<Collection<Puzzle>> method(Collection<Puzzles> puzzles) {
Map<Wrapper,<Collection<Puzzle>> map = new HashMap<Wrapper,<Collection<Puzzle>>();
for (Puzzle each: puzzles) {
Wrapper wrapper = new Wrapper(each);
Collection<Puzzle> coll = map.get(wrapper);
if (coll == null) map.put(wrapper, coll = new ArrayList<Puzzle>());
coll.add(puzzle);
}
return map.values();
}
答案 1 :(得分:2)
好的,你有办法测量物体之间的相似性。这意味着它们形成Metric Space。
问题是,你的空间是Euclidean space还是正常的三维空间,还是整数或类似的东西?如果是,那么您可以使用binary space partition来获得多个维度。
(问题是,基本上:你的物体和n维实数矢量之间是否存在同态?如果是,那么你可以使用技术来测量n维空间中点的紧密度。)
现在,如果不是欧洲空间那么你就会遇到更大的问题。程序员可能最熟悉的非欧几里德空间的一个例子是字符串之间的Levenshtein Distance。
如果您的问题类似于查看字符串与已存在字符串列表的相似程度,那么我不会知道任何没有O(n 2)的算法)时间。也许那里有一些。
但另一个重要问题是:你有多少时间?有多少个物体?如果您有时间或者您的数据集足够小以至于O(n 2 )算法是可行的,那么您只需迭代对象列表以查看它是否低于某个阈值。如果是这样,请拒绝它。
只需重载AbstractCollection并替换Add函数。使用ArrayList或其他。你的代码看起来有点像这样
class SimilarityRejector<T> extends AbstractCollection<T>{
ArrayList<T> base;
double threshold;
public SimilarityRejector(double threshold){
base = new ArrayList<T>();
this.threshold = threshold;
}
public void add(T t){
boolean failed = false;
for(T compare : base){
if(similarityComparison(t,compare) < threshold) faled = true;
}
if(!failed) base.add(t);
}
public Iterator<T> iterator() {
return base.iterator();
}
public int size() {
return base.size();
}
}
等。显然,T需要是某个类的子类,您可以对其进行比较。如果您有欧几里德指标,那么您可以使用空间分区,而不是遍历其他所有项目。
答案 2 :(得分:2)
答案 3 :(得分:0)
通常情况下,“相似性”不是传递关系。因此,第一步是从等效性而非相似性的角度来考虑这一点。等价是反身的,对称的和传递的。
这里的简单方法是定义一个拼图包装器,其equals()和hashCode()方法是根据所讨论的等价关系实现的。
完成后,将包装好的对象放入java.util.Set并过滤掉重复的内容。
答案 4 :(得分:0)
但如果您想亲自制作,那么这似乎是最简单,最清晰的解决方案:
/**
* Distinct input list values (cuts duplications)
* @param items items to process
* @param comparator comparator to recognize equal items
* @return new collection with unique values
*/
public static <T> Collection<T> distinctItems(List<T> items, Comparator<T> comparator) {
List<T> result = new ArrayList<>();
for (int i = 0; i < items.size(); i++) {
T item = items.get(i);
boolean exists = false;
for (int j = 0; j < result.size(); j++) {
if (comparator.compare(result.get(j), item) == 0) {
exists = true;
break;
}
}
if (!exists) {
result.add(item);
}
}
return result;
}