【问题标题】:How to store a set of unique integer arrays in java如何在java中存储一组唯一的整数数组
【发布时间】:2019-10-28 09:22:53
【问题描述】:

我正在尝试在 java 中存储唯一整数数组的列表。我不能使用哈希集,因为 .equals 方法不会等同于具有相同值但引用不同的 int[]。

【问题讨论】:

    标签: java arrays integer equals


    【解决方案1】:

    一种选择是使用List<Integer> 而不是int[] 作为Set 的元素,这样您就可以使用任何Set 实现。

    如果您必须使用数组,您可以将它们存储在 TreeSet<int[]> 中,并将自定义 Comparator<int[]> 传递给 TreeSet 构造函数。这应该可行,因为TreeSet 不使用equals()hashCode() 来确定两个元素是否相同。

    【讨论】:

    【解决方案2】:

    我认为以下 sn-p 将是您的解决方案。如果我猜对了

    List<Integer> numberList = new ArrayList<Integer>();
    int[] myInts = {1, 1, 2, 3, 3, 3, 3, 4};
    for (int i : myInts) {
      if (!numberList.contains(i)) {
         numberList.add(i);
       }
    }
    

    【讨论】:

      【解决方案3】:

      您可以将int[] 数组包装在覆盖equalshashCode 的特殊容器中:

      public class IntArrayHolder {
          private final int[] array;
      
          public IntArrayHolder(int[] array) {
              this.array = array;
          }
      
          public int[] getArray() {
              return array;
          }
      
          @Override
          public boolean equals(Object object) {
              if (this == object) return true;
              if (!(object instanceof IntArrayHolder)) return false;
              IntArrayHolder that = (IntArrayHolder) object;
              return Arrays.equals(array, that.array);
          }
      
          @Override
          public int hashCode() {
              return Arrays.hashCode(array);
          }
      }
      

      并使用Set&lt;IntArrayHolder&gt; 而不是Set&lt;int[]&gt;

      Set<IntArrayHolder> set = new HashSet<>();
      set.add(new IntArrayHolder(new int[]{0}));
      set.add(new IntArrayHolder(new int[]{0}));
      set.add(new IntArrayHolder(new int[]{1}));
      set.forEach(elm -> System.out.println(Arrays.toString(elm.getArray()))); // prints [1][0]
      

      您还可以将包装和展开封装在特殊的泛型类中,并以这种方式使用它们:

      Set<int[]> set = new MappedSet<>(new HashSet<>(), Mapper.from(
              IntArrayHolder::getArray,
              IntArrayHolder::new
      ));
      set.add(new int[]{0});
      set.add(new int[]{0});
      set.add(new int[]{1});
      set.forEach(elm -> System.out.println(Arrays.toString(elm))); // prints [1][0]
      

      这里有MapperMappedSetMappedCollectionMappedIterableMappedIteratorMappedArray

      /**
       * <h1>Mapper</h1>
       * Represents a two way function which can be used for adapting
       * {@code Type<A>} to {@code Type<B>} where {@code Type} is invariant
       * generic type.
       *
       * <h2>Invertibility</h2>
       * <p>
       * If this mapper isn't bounded result of performing {@code out(in(x))} should
       * be similar to {@code x}, no guarantees are made about their equality. The same goes
       * with {@code in(out(x))}.
       *
       * <h2>Nullability</h2>
       * <p>
       * A mapper always converts {@code null} to {@code null} and non-null references to non-null
       * references. {@code null} can be passed to {@link #out(A)} and {@link #in(B)} methods, but
       * should never be passed to {@link #doOut(A)} and {@link #doIn(B)}.
       *
       * <h2>Bounded wildcards</h2>
       * <p>
       * Bounded wildcards should never be used on {@link A} type parameter, because mapper with bounded
       * {@link A} can't be accepted by any adapter and is completely useless.
       *
       * <p>Using of bounded wildcard on {@link B} type parameter indicates that mapper can perform
       * operations in only one way see {@link #outMapper(Function)} and {@link #inMapper(Function)}.
       *
       * <h2>Unchecked functionality</h2>
       * A mapper provides unchecked functionality for not generified methods via {@link #uncheckedOut(Object)},
       * {@link #uncheckedIn(Object)} and {@link #unchecked()} methods.
       * <p>Restricting unchecked functionality can be done by using {@link #restrictAClass(Class)}
       * and {@link #restrictBClass(Class)} methods.
       *
       * <h2>Instantiation</h2>
       * The following factory methods can be used for mapper instantiation:
       * <ul>
       *     <li>{@link #from(Function, Function)} - two ways mapper</li>
       *     <li>{@link #outMapper(Function)} - only-out mapper</li>
       *     <li>{@link #inMapper(Function)} - only-in mapper</li>
       * </ul>
       * <p>This interface can also be implemented from outside.
       *
       * @param <A> type parameter of adapted generic instance
       * @param <B> type parameter of generic adapter
       */
      public interface Mapper<A, B> extends Function<A, B> {
          /**
           * Adapts return value of adapted instance method to adapter type.
           *
           * @param a result of calling adapted instance method
           * @return result which should be return from adapter
           * @implNote this method isn't supposed to be overridden, instead {@link #doOut(A)}
           * method should be implemented for defining mapper behaviour
           */
          @Contract("null -> null; !null -> !null")
          @Final
          default @Nullable B out(@Nullable A a) {
              return a == null ? null : doOut(a);
          }
      
          /**
           * Adapts input argument of adapter method to adapted instance type.
           *
           * @param b argument passed to adapter method
           * @return argument which should be passed to adapted instance
           * @implNote this method isn't supposed to be overridden, instead {@link #doIn(B)}
           * method should be implemented for defining mapper behaviour
           */
          @Contract("null -> null; !null -> !null")
          @Final
          default @Nullable A in(@Nullable B b) {
              return b == null ? null : doIn(b);
          }
      
          /**
           * Adapts return value of not generified adapted instance method to adapter type,
           * uses unchecked cast.
           *
           * @param a result of calling adapted instance method, is to have {@link A} type
           * @return result which should be return from adapter
           * @see #out(A)
           */
          @SuppressWarnings("unchecked") // unchecked is indicated in the method name
          @Contract("null -> null; !null -> !null")
          @Final
          default @Nullable B uncheckedOut(@Nullable Object a) {
              return out((A) a);
          }
      
          /**
           * Adapts input argument of not generified adapter method to adapted instance type,
           * uses unchecked cast.
           *
           * @param b argument passed to adapter method, is to have {@link B} type
           * @return argument which should be passed to adapted instance
           * @see #in(B)
           */
          @SuppressWarnings("unchecked") // unchecked is indicated in the method name
          @Contract("null -> null; !null -> !null")
          @Final
          default @Nullable A uncheckedIn(@Nullable Object b) {
              return in((B) b);
          }
      
          /**
           * Performs adapting of {@link A} to {@link B}.
           *
           * @param a input argument, mustn't be {@code null}
           * @return adaptation result, mustn't be {@code null}. If adaptation has failed {@link IllegalArgumentException}
           * should be thrown or null-object should be returned.
           * @apiNote this method isn't supposed to be called, instead {@link #out(A)} method should be used
           * @implNote this method is supposed to be implemented for defining {@link #out(A)} method behaviour
           * @see #out(A)
           */
          @NotNull B doOut(@NotNull A a);
      
          /**
           * Performs adapting of {@link B} to {@link A}.
           *
           * @param b input argument, mustn't be {@code null}
           * @return adaptation result, mustn't be {@code null}. If adaptation has failed {@link IllegalArgumentException}
           * should be thrown or null-object should be returned.
           * @apiNote this method isn't supposed to be called, instead {@link #in(B)} method should be used
           * @implNote this method is supposed to be implemented for defining {@link #in(B)} method behaviour
           * @see #in(B)
           */
          @NotNull A doIn(@NotNull B b);
      
          /**
           * Non-null analog of {@link #out(A)}.
           *
           * @param a input argument
           * @return mapping result
           * @apiNote {@code mapper::apply} shouldn't be used, instead mapper instance itself
           * should be used as a {@code Function<A, B>}
           */
          @Override
          default @NotNull B apply(@NotNull A a) {
              return out(a);
          }
      
          /**
           * Non-null analog of {@link #in(B)}.
           *
           * @param b input argument
           * @return mapping result
           * @apiNote {@code mapper::undo} shouldn't be used, instead {@link #reverse()}
           * should be used as a {@code Function<B, A>}
           */
          default @NotNull A undo(@NotNull B b) { return in(b); }
      
          /**
           * Returns reverse view of this mapper.
           * <p>Some mappers may perform reverse view caching, so it's likely that
           * {@code mapper.reverse() == mapper.reverse()} and {@code mapper.reverse().reverse() == mapper}
           * will be true.
           *
           * @return reverse view of this mapper
           */
          default Mapper<B, A> reverse() {
              return new Mapper<B, A>() {
                  @Override
                  public @NotNull A doOut(@NotNull B b) {
                      return Mapper.this.doIn(b);
                  }
      
                  @Override
                  public @NotNull B doIn(@NotNull A a) {
                      return Mapper.this.doOut(a);
                  }
      
                  @Override
                  public Mapper<A, B> reverse() {
                      return Mapper.this;
                  }
              };
          }
      
          /**
           * Returns this mapper after unchecked casting to required type.
           * <p>Should be used carefully: sometimes {@link #reverse()}{@code .unchecked()} is required instead
           * of {@code unchecked()}.
           *
           * @param <A2> {@link A} type parameter of returned mapper
           * @return this instance
           * @see #uncheckedIn(Object)
           * @see #uncheckedOut(Object)
           */
          @SuppressWarnings("unchecked") // unchecked is indicated in the method name
          @Contract(value = "-> this", pure = true)
          default <A2> Mapper<A2, B> unchecked() {
              return (Mapper<A2, B>) this;
          }
      
          @SuppressWarnings("unchecked") // unchecked is indicated in the method name
          default <A2, B2> Mapper<A2, B2> doubleUnchecked() {
              return (Mapper<A2, B2>) this;
          }
      
          /**
           * Creates a composed mapper from {@link V} to {@link B} which uses {@code before}
           * mapper and this mapper in order required by operations.
           *
           * @param <V>    the first type parameter of {@code before} mapper, and of the
           *               composed mapper
           * @param before the additional mapper
           * @return a composed mapper
           * @see #andThenMapper(Mapper)
           * @see #compose(Function)
           */
          @Contract(value = "_ -> new", pure = true)
          default <V> Mapper<V, B> composeMapper(Mapper<V, A> before) {
              return before.andThenMapper(this);
          }
      
          /**
           * Creates a composed mapper from {@link A} to {@link C} which uses this
           * mapper and {@code after} mapper in order required by operations.
           *
           * @param <C>   the second type parameter of {@code after} mapper, and of the
           *              composed mapper
           * @param after the additional mapper
           * @return a composed mapper
           * @see #composeMapper(Mapper)
           * @see #andThen(Function)
           */
          @Contract(value = "_ -> new", pure = true)
          default <C> Mapper<A, C> andThenMapper(Mapper<B, C> after) {
              return from(a -> after.out(out(a)), c -> in(after.in(c)));
          }
      
          /**
           * Creates mapper which restricts {@link A} class, so type of {@link #out(A)} operation parameter
           * is checked before performing operation.
           * <p>If parameter isn't an {@code instanceof clazz} {@link #uncheckedMap(Object)} is used.
           *
           * @param clazz {@link A} class
           * @return mapper which restricts {@link A} class
           * @see #restrictBClass(Class)
           */
          @Contract(value = "_ -> new", pure = true)
          default Mapper<A, B> restrictAClass(Class<A> clazz) {
              return from(a -> clazz.isAssignableFrom(a.getClass()) ? doOut(a) : uncheckedMap(a), this::doIn);
          }
      
          /**
           * Creates mapper which restricts {@link B} class, so type of {@link #in(B)} operation parameter
           * is checked before performing operation.
           * <p>If parameter isn't an {@code instanceof clazz} {@link #uncheckedMap(Object)} is used.
           *
           * @param clazz {@link B} class
           * @return mapper which restricts {@link B} class
           * @see #restrictAClass(Class)
           */
          @Contract(value = "_ -> new", pure = true)
          default Mapper<A, B> restrictBClass(Class<B> clazz) {
              return from(this::doOut, b -> clazz.isAssignableFrom(b.getClass()) ? doIn(b) : uncheckedMap(b));
          }
      
          /**
           * Creates mapper from given functions.
           *
           * @param out function for performing {@link #doOut(A)} method
           * @param in  function for performing {@link #doIn(B)} method
           * @param <A> returned mapper first type parameter
           * @param <B> returned mapper second type parameter
           * @return created mapper
           */
          @Contract(value = "_, _ -> new", pure = true)
          static <A, B> Mapper<A, B> from(Function<? super A, ? extends B> out, Function<? super B, ? extends A> in) {
              return new Mapper<A, B>() {
                  private @Nullable Mapper<B, A> reverse = null;
      
                  @Override
                  public @NotNull B doOut(@NotNull A a) {
                      return out.apply(a);
                  }
      
                  @Override
                  public @NotNull A doIn(@NotNull B b) {
                      return in.apply(b);
                  }
      
                  @Override
                  public Mapper<B, A> reverse() {
                      return (reverse == null) ? (reverse = Mapper.super.reverse()) : reverse;
                  }
              };
          }
      
          /**
           * Creates mapper that can only normally perform {@link #out(A)} operation.
           *
           * <p>The returned mapper is bounded so {@link #in(B)} operation without using <i>unchecked functionality</i>
           * can only be called with {@code null} argument, according to the contract this will lead to
           * returning of {@code null}.
           *
           * @param out function for performing {@link #doOut(A)} method
           * @param <A> returned mapper first type parameter
           * @param <B> returned mapper second type parameter
           * @return mapper that only provides {@link #out(A)} operation
           */
          @Contract(value = "_ -> new", pure = true)
          static <A, B> Mapper<A, ? extends B> outMapper(Function<? super A, ? extends B> out) {
              return from(out, Mapper::uncheckedMap);
          }
      
          /**
           * Creates mapper that can only normally perform {@link #in(B)} operation.
           *
           * <p>The returned mapper is bounded so {@link #out(A)} result can be used only as {@link Object}.
           * <p>Returned mapper guarantees that {@code out(x) == x} will always be {@code true}.
           *
           * @param in  function for performing {@link #doIn(B)} method
           * @param <A> returned mapper first type parameter
           * @param <B> returned mapper second type parameter
           * @return mapper that only provides {@link #in(B)} operation
           */
          @Contract(value = "_ -> new", pure = true)
          static <A, B> Mapper<A, ? super B> inMapper(Function<? super B, ? extends A> in) {
              return from(Mapper::uncheckedMap, in);
          }
      
          /**
           * Creates mapper that maps any object to itself.
           *
           * @param <T> returned mapper type parameter
           * @return created mapper
           */
          @Contract(value = "-> new", pure = true)
          static <T> Mapper<T, T> identity() {
              return from(Function.identity(), Function.identity());
          }
      
          /**
           * Performs unchecked cast of input to required type,
           * this method may also do some logging.
           *
           * <p>This method is supposed to be used when impossible to call {@code Function<? extends A, B>} or
           * returning {@link Object} {@code Function<A, ? super B>} is needed.
           *
           * <p>In some cases it can also be called when {@code a} appeared to be not an {@code instanceof Class<A>}.
           *
           * @param a   input argument
           * @param <A> input argument type
           * @param <B> required type
           * @return result of unchecked cast
           * @deprecated unchecked cast
           */
          @SuppressWarnings({"Contract", "unchecked"}) // unchecked is indicated in the method name
          @Contract("_ -> param1")
          @Deprecated
          @WarnOnUse(exceptClasses = Mapper.class)
          static <A, B> B uncheckedMap(A a) {
              return (B) a;
          }
      }
      
      public class MappedSet<E, E2> extends MappedCollection<E, E2> implements Set<E2> {
          public MappedSet(Set<E> set, Mapper<E, E2> mapper) {
              super(set, mapper);
          }
      
          public static <E, E2> Set<E2> map(Set<E> inst, Mapper<E, E2> mapper) {
              return new MappedSet<>(inst, mapper);
          }
      
          public static <E, E2> Set<? extends E2> mapOut(Set<? extends E> inst, Function<? super E, ? extends E2> mapper) {
              return map(inst, Mapper.outMapper(mapper));
          }
      
          public static <E, E2> Set<? super E2> mapIn(Set<? super E> inst, Function<? super E2, ? extends E> mapper) {
              return map(inst, Mapper.inMapper(mapper));
          }
      }
      
      public class MappedCollection<E, E2> extends MappedIterable<E, E2> implements Collection<E2> {
          private final Collection<E> collection;
          private final Mapper<E, E2> mapper;
      
          public MappedCollection(Collection<E> collection, Mapper<E, E2> mapper) {
              super(collection, mapper);
              this.collection = collection;
              this.mapper = mapper;
          }
      
          public static <E, E2> Collection<E2> map(Collection<E> inst, Mapper<E, E2> mapper) {
              return new MappedCollection<>(inst, mapper);
          }
      
          public static <E, E2> Collection<? extends E2> mapOut(Collection<? extends E> inst, Function<? super E, ? extends E2> mapper) {
              return map(inst, Mapper.outMapper(mapper));
          }
      
          public static <E, E2> Collection<? super E2> mapIn(Collection<? super E> inst, Function<? super E2, ? extends E> mapper) {
              return map(inst, Mapper.inMapper(mapper));
          }
      
          @Override
          public int size() {
              return collection.size();
          }
      
          @Override
          public boolean isEmpty() {
              return collection.isEmpty();
          }
      
          @Override
          public boolean contains(Object o) {
              return collection.contains(mapper.uncheckedIn(o));
          }
      
          @Override
          public @NotNull Object[] toArray() {
              return MappedArray.map(collection.toArray(), mapper.unchecked());
          }
      
          @Override
          public @NotNull <T> T[] toArray(@NotNull T[] a) {
              return MappedArray.map(collection.toArray(), ContainersUtils.getComponentType(a), mapper.doubleUnchecked());
          }
      
          @Contract(mutates = "this")
          @Override
          public boolean add(@NotNull E2 e2) {
              return collection.add(mapper.in(e2));
          }
      
          @Contract(mutates = "this")
          @Override
          public boolean remove(Object o) {
              return collection.remove(mapper.uncheckedIn(o));
          }
      
          @Override
          public boolean containsAll(@NotNull Collection<?> c) {
              return collection.containsAll(map(c, mapper.reverse().unchecked()));
          }
      
          @Contract(mutates = "this")
          @Override
          public boolean addAll(@NotNull Collection<? extends E2> c) {
              return collection.addAll(mapOut(c, mapper.reverse()));
          }
      
          @Contract(mutates = "this")
          @Override
          public boolean removeAll(@NotNull Collection<?> c) {
              return collection.removeAll(map(c, mapper.reverse().unchecked()));
          }
      
          @Contract(mutates = "this")
          @Override
          public boolean retainAll(@NotNull Collection<?> c) {
              return collection.retainAll(map(c, mapper.reverse().unchecked()));
          }
      
          @Contract(mutates = "this")
          @Override
          public void clear() {
              collection.clear();
          }
      }
      
      @RequiredArgsConstructor
      public class MappedIterable<E, E2> implements Iterable<E2> {
          private final @NotNull Iterable<E> iterable;
          private final @NotNull Function<? super E, ? extends E2> mapper;
      
          public static <E, E2> Iterator<E2> map(Iterator<E> inst, Function<? super E, ? extends E2> mapper) {
              return new MappedIterator<>(inst, mapper);
          }
      
          @Override
          public @NotNull Iterator<E2> iterator() {
              return MappedIterator.map(iterable.iterator(), mapper);
          }
      }
      
      @RequiredArgsConstructor
      public class MappedIterator<E, E2> implements Iterator<E2> {
          private final @NotNull Iterator<E> iterator;
          private final @NotNull Function<? super E, ? extends E2> mapper;
      
          public static <E, E2> Iterator<E2> map(Iterator<E> inst, Function<? super E, ? extends E2> mapper) {
              return new MappedIterator<>(inst, mapper);
          }
      
          @Contract(pure = true)
          @Override
          public boolean hasNext() {
              return iterator.hasNext();
          }
      
          @Override
          public E2 next() {
              return mapper.apply(iterator.next());
          }
      }
      
      @UtilityClass
      public class MappedArray {
          public static <T> Object[] map(T[] inst, Function<? super T, ?> mapper) {
              return Stream.of(inst).map(mapper).toArray();
          }
      
          public static <T, T2> T2[] map(T[] inst, Class<T2> clazz, Function<? super T, ? extends T2> mapper) {
              return Stream.of(inst).map(mapper).toArray(i -> ContainersUtils.createArray(clazz, i));
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-12
        • 2017-10-18
        • 1970-01-01
        • 2016-04-30
        • 1970-01-01
        相关资源
        最近更新 更多