Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/368.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:如何将集合划分为等价类?_Java_Grouping - Fatal编程技术网

Java:如何将集合划分为等价类?

Java:如何将集合划分为等价类?,java,grouping,Java,Grouping,我有一个项目列表(!): A B C D E 我想把他们分组: [A、C、D] [乙,戊] 组的定义如下: 根据自定义函数f(a,b)->布尔值,组中的所有项都相等 f(a,b)=f(b,a) 问题:是否有现成的API可以这样做 <T> List<List<T>> group(Collection<T> collection, BiFunction<T, T, Boolean> eqF); 列表组(集合集合,双功能eq

我有一个项目列表(!):

  • A
  • B
  • C
  • D
  • E
我想把他们分组:

  • [A、C、D]
  • [乙,戊]
组的定义如下:

  • 根据自定义函数f(a,b)->布尔值,组中的所有项都相等
  • f(a,b)=f(b,a)
问题:是否有现成的API可以这样做

<T> List<List<T>> group(Collection<T> collection, BiFunction<T, T, Boolean> eqF);
列表组(集合集合,双功能eqF);
更新。这个问题完全不适用于您可以定义一些质量来分组的场景在本例中,Java 8 Collectors.groupingBy是最简单的答案

我正在使用多维向量,等式函数如下所示:

  • 指标(a,b)<阈值

在这种情况下,定义散列等于解决初始任务:)

您可以使用散列在线性时间内完成此操作

为此,您需要首先在对象中实现
hashCode()
函数,以便它为相等的元素返回相等的哈希值(例如,通过对其实例属性的哈希代码进行异或运算)。然后可以使用集合的哈希表对元素进行分组

Map<Integer, Set<T>> hashMap = new HashMap<>();
for (T element : collection) {
    if (!hashMap.containsKey(element.hashCode())
         hashMap.put(element.hashCode(), new HashSet<T>());
    hashMap.get(element.hashCode()).add(element);
}
Map hashMap=new hashMap();
for(T元素:集合){
if(!hashMap.containsKey(element.hashCode())
put(element.hashCode(),new HashSet());
获取(element.hashCode()).add(element);
}
当相等的元素产生相同的散列时,它们将被插入到相同的等价类中


现在,您可以使用
hashMap.values();

获得所有等价类(作为集合)的集合。我还建议您实现一种哈希机制。您可以使用番石榴进行类似的操作:

fluenterable.from(集合)
.index(新函数(){
K应用(T输入){
//将T转换为K散列
}
})//这将返回ImmutableListMultimap
.asMap()//将返回映射
.values();//集合

我很确定标准API中没有关于此的内容。您可以尝试第三方收集类,如Trove的(有趣的是,根据中的一条评论,番石榴集团(目前)拒绝了类似的类。请参阅讨论。)

另一种方法是滚动您自己的解决方案。如果您没有太多的项目,我建议使用蛮力方法:保留一个项目列表,对于每个新项目,检查列表列表,看看它是否等于列表的第一个元素。如果是,将新项目添加到匹配列表中,如果不是,则将新项目添加到列表中计算复杂度不是很好,这就是为什么我只建议在项目数量较少或执行时间性能根本不成问题的情况下使用该项


第二种方法是修改item类以实现自定义相等函数。但要将其用于基于哈希的集合类,还需要重写
hashcode()
。(如果不使用基于哈希的集合,最好使用蛮力方法。)如果不想(或不能)修改item类(例如,您想要使用各种相等测试),我建议创建一个包装器类,可以使用相等(和散列代码)策略对其进行参数化(这是修改item类和使用Trove类之间的一种折衷)

下面是一个简单的字符串分组示例。如果要分组的对象更复杂,则需要提供不同于
identity()
的函数

public class StreamGroupingBy
{

   public static void main( String[] args )
   {
      List<String> items = Arrays.asList(  
              "a", "b", "c", "d", 
              "a", "b", "c",
              "a", "b", 
              "a", "x" );

      Map<String,List<String>> result = items.stream().collect(
              Collectors.groupingBy( Function.identity() ) );
      System.out.println( result );
   }
}

您的场景听起来像是
groupingBy
收集器的一个很好的用例。通常情况下,您不提供相等函数,而是提供一个提取限定符的函数。然后元素映射到列表中的这些限定符

i、 e

你可以使用它,比如:

Collection<List<T>> result
    = list.stream()
        .collect(Collectors.groupingBy(
            AlternateIdentity.mapper(eqF, hashF)
        ))
        .values();
采集结果
=list.stream()
.collect(收集器.groupingBy(
AlternateIdentity.mapper(eqF,hashF)
))
.values();

其中,
eqF
是您的函数,
hashF
是一个散列代码函数,它散列与
eqF
测试相同的字段。(同样,您也可以在
hashF
中返回
0
,但有一个正确的实现会加快速度。)

如果用于对元素进行分组的自定义函数返回布尔值,您怎么会有两个以上的组?@Tunaki-这被称为划分为等价类。假设对象是整数,相等(真/假)计算为模3(即,如果它们有相同的余数,则相等)。然后,从1到100的整数将在三个存储桶中结束,即使这是一个二进制相等测试。例如,有一个F元素,它不等于任何其他元素。它由一个元素组成一组。响应您的更新:您确定这里有等价关系吗?通常,
metrics(a,b)
是不可传递的,除非您的空间具有满足某些不寻常约束的结构。如果测试甚至不是对称的,那么您就没有度量标准。分组项(1)与您真正尝试完成的内容和(2)有何关联理论上甚至可能?听起来你是在寻求一个与你的根本问题无关的问题Y的解决方案。你可能想删除这个问题,然后发布一个不同的问题来描述你真正想要的。编写一个合适的哈希代码并不容易。(您的建议不起作用,因为如果自定义相等函数这么说,则具有不同字段的项需要使用相同的哈希代码。)此外,如果OP需要使用不同的相等性测试来处理相同的项目列表,那么这将不起作用。强制依赖特定的
hashCode
函数是很糟糕的,非常糟糕。equals/hashCode shou
{a=[a, a, a, a], b=[b, b, b], c=[c, c], d=[d], x=[x]}
Map<Qualifier, List<T>> map = list.stream()
    .collect(Collectors.groupingBy(T::getQualifier));

Collection<List<T>> result = map.values();
interface AlternateIdentity<T> {    
    public static <T> Function<T, AlternateIdentity<T>> mapper(
            BiPredicate<? super T, Object> equality, ToIntFunction<? super T> hasher) {
        return t -> new AlternateIdentity<T>() {
            @Override
            public boolean equals(Object other) {
                return equality.test(t, other);
            }

            @Override
            public int hashCode() {
                return hasher.applyAsInt(t);
            }
        };
    }
}
Collection<List<T>> result
    = list.stream()
        .collect(Collectors.groupingBy(
            AlternateIdentity.mapper(eqF, hashF)
        ))
        .values();