使用Guava索引可以匹配多属性的字段

Using Guava to index fields that can match multi properties

我们有一组计划要根据 3 个属性编制索引。每个值都可以有任何值的组合,到目前为止,它们只能是 3 个中的 1 个。我们希望能够使用 Guava,因为这是公司的代码标准,因此我需要尽我最大的努力将它用于任何循环。 Products 集合可能非常大,因此我们希望尽可能减少循环数量。这是我们拥有的:

private static Function<Product, ProductType> TO_PRODUCT_TYPE = 
    new Function<Product, ProductType>()
{
  @Override
  public ProductType apply(Product product)
  {
    if (product.isOne())
    {
      return ProductType.ONE;
    }
    else if (product.isTwo())
    {
      return ProductType.TWO;
    }
    else if (product.isThree())
    {
      return ProductType.THREE;
    }
    return null;
  };
}
...
Multimap<ProductType, Product> productsByType = Multimaps.index(products, TO_PRODUCT_TYPE);
List<Product> oneProducts = (List<Product>) productsByType.get(SINGLE);
List<Product> twoProducts = (List<Product>) productsByType.get(ProductType.TWO);
List<Product> threeProducts = (List<Product>) productsByType.get(ProductType.THREE);

但是,如果每种类型只有一种,这也是可行的。如果有多种可能性,有没有办法索引?例如,如果 Product 1 既是 ONE 又是 TWO,那么它将同时出现在 oneProducts 和 twoProducts 中。

ImmutableListMultimap.Builder<ProductType, Product> builder =
    ImmutableListMultimap.builder();
for (Product product : products) {
  if (product.isOne()) {
    builder.put(ProductType.ONE, product);
  }
  if (builder.isTwo()) {
    builder.put(ProductType.TWO, product);
  }
  // ...

  // or better, if possible:
  for (ProductType type : product.getTypes()) {
    builder.put(type, product);
  }
}
ImmutableListMultimap<ProductType, Product> productsByType = builder.build();

Guava 目前未提供此功能,但您可以随时复制 Multimaps.index(...) 并创建自己的 multiIndex(...):

public static <K, V> ImmutableListMultimap<K, V> multiIndex(
        Iterable<V> values, Function<? super V, ? extends Iterable<? extends K>> keysFunction) {
    return multiIndex(values.iterator(), keysFunction);
}

public static <K, V> ImmutableListMultimap<K, V> multiIndex(
        Iterator<V> values, Function<? super V, ? extends Iterable<? extends K>> keysFunction) {
    checkNotNull(keysFunction);
    ImmutableListMultimap.Builder<K, V> builder = ImmutableListMultimap.builder();
    while (values.hasNext()) {
        V value = values.next();
        checkNotNull(value, values);
        Iterable<? extends K> keys = keysFunction.apply(value);
        checkNotNull(keys, value);
        for (K key : keys) {
            builder.put(key, value);
        }
    }
    return builder.build();
}

然后您可以通过将 TO_PRODUCT_TYPE 更新为 TO_PRODUCT_TYPES:

来使用它
private static Function<Product, EnumSet<ProductType>> TO_PRODUCT_TYPES =
        new Function<Product, EnumSet<ProductType>>() {
            @Override
            public EnumSet<ProductType> apply(Product product) {
                EnumSet<ProductType> productTypes = EnumSet.noneOf(ProductType.class);
                if (product.isOne()) {
                    productTypes.add(ProductType.ONE);
                }
                if (product.isTwo()) {
                    productTypes.add(ProductType.TWO);
                }
                if (product.isThree()) {
                    productTypes.add(ProductType.THREE);
                }
                return productTypes;
            }
        };
...
Multimap<ProductType, Product> productsByType = multiIndex(products, TO_PRODUCT_TYPES);
List<Product> oneProducts = (List<Product>) productsByType.get(ProductType.ONE);
List<Product> twoProducts = (List<Product>) productsByType.get(ProductType.TWO);
List<Product> threeProducts = (List<Product>) productsByType.get(ProductType.THREE);

请注意,这将忽略没有类型的产品。