All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bbn.bue.common.collections.MapUtils Maven / Gradle / Ivy

There is a newer version: 4.1.2
Show newest version
package com.bbn.bue.common.collections;

import com.bbn.bue.common.StringUtils;
import com.bbn.bue.common.collections.IterableUtils.ZipPair;

import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Ordering;

import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import static com.google.common.base.Preconditions.checkNotNull;

public final class MapUtils {

  private MapUtils() {
    throw new UnsupportedOperationException();
  }

  /**
   * Pairs up the values of a map by their common keys.
   */
  public static  PairedMapValues zipValues(final Map left, final Map right) {
    checkNotNull(left);
    checkNotNull(right);
    final ImmutableList.Builder> pairedValues =
        ImmutableList.builder();
    final ImmutableList.Builder leftOnly = ImmutableList.builder();
    final ImmutableList.Builder rightOnly = ImmutableList.builder();

    for (final Map.Entry leftEntry : left.entrySet()) {
      final K key = leftEntry.getKey();
      if (right.containsKey(key)) {
        pairedValues.add(ZipPair.from(leftEntry.getValue(), right.get(key)));
      } else {
        leftOnly.add(leftEntry.getValue());
      }
    }

    for (final Map.Entry rightEntry : right.entrySet()) {
      if (!left.containsKey(rightEntry.getKey())) {
        rightOnly.add(rightEntry.getValue());
      }
    }

    return new PairedMapValues(pairedValues.build(), leftOnly.build(),
        rightOnly.build());
  }

  /**
   * Return a copy of the input map with keys transformed by {@code keyInjection} and values
   * transformed by {@code valueFunction}. Beware: {@code keyInjection} must be an injection over
   * all the keys of the input map. If two original keys are mapped to the same value, an {@link
   * java.lang.IllegalArgumentException} will be returned.
   *
   * Neither {@code keyInjection} nor {@code valueFunction} may return null. If one does, an
   * exception will be thrown.
   */
  public static  ImmutableMap copyWithTransformedEntries(Map input,
      Function keyInjection, Function valueFunction) {
    final ImmutableMap.Builder ret = ImmutableMap.builder();

    for (final Map.Entry entry : input.entrySet()) {
      ret.put(keyInjection.apply(entry.getKey()), valueFunction.apply(entry.getValue()));
    }
    return ret.build();
  }

  public static class PairedMapValues {

    public PairedMapValues(final List> pairedValues, final List leftOnly,
        final List rightOnly) {
      this.pairedValues = ImmutableList.copyOf(pairedValues);
      this.leftOnly = ImmutableList.copyOf(leftOnly);
      this.rightOnly = ImmutableList.copyOf(rightOnly);
    }

    public List> pairedValues() {
      return pairedValues;
    }

    public List leftOnly() {
      return leftOnly;
    }

    public List rightOnly() {
      return rightOnly;
    }

    public boolean perfectlyAligned() {
      return leftOnly.isEmpty() && rightOnly.isEmpty();
    }

    private final List> pairedValues;
    private final List leftOnly;
    private final List rightOnly;
  }

  public static  ImmutableSet allKeys(final Iterable> maps) {
    final ImmutableSet.Builder builder = ImmutableSet.builder();

    for (final Map map : maps) {
      builder.addAll(map.keySet());
    }

    return builder.build();
  }

  public static  Function, V> getEntryValue() {
    return new Function, V>() {
      @Override
      public V apply(final Map.Entry entry) {
        return entry.getValue();
      }
    };
  }

  public static  Function, K> getEntryKey() {
    return new Function, K>() {
      @Override
      public K apply(final Map.Entry entry) {
        return entry.getKey();
      }
    };
  }

  public static  Function, Iterable> getValues() {
    return new Function, Iterable>() {
      @Override
      public Iterable apply(final Map input) {
        return input.values();
      }
    };
  }

  public static > Ordering> byValueOrderingAscending() {
    return Ordering.natural().onResultOf(MapUtils.getEntryValue());
  }

  public static > Ordering> byValueOrderingDescending() {
    return Ordering.natural().onResultOf(MapUtils.getEntryValue()).reverse();
  }

  public static  Ordering> byValueOrdering(final Ordering valueOrdering) {
    return valueOrdering.onResultOf(MapUtils.getEntryValue());
  }

  public static  List> sortedCopyOfEntries(final Map map,
      final Ordering> ordering) {
    return ordering.sortedCopy(map.entrySet());
  }

  public static , V> Ordering> byKeyDescendingOrdering() {
    return Ordering.natural().onResultOf(MapUtils.getEntryKey());
  }

  public static  Ordering> byKeyOrdering(Ordering keyOrdering) {
    return keyOrdering.onResultOf(MapUtils.getEntryKey());
  }

  /**
   * Returns a new map which is contains all the mappings in both provided maps. This method will
   * throw an exception if there is any key {@code K} such that {@code K} is a key in both maps and
   * {@code !first.get(K).equals(second.get(K))}.    The iteration order of the resulting map will
   * contain first all entries in the first map in the order provided by {@code first.entrySet()}
   * followed by all non-duplicate entries in the second map in the order provided by {@code
   * second.entrySet()}.  This method is null-intolerant: if either input map contains {@code null},
   * an exception will be thrown.
   */
  public static  ImmutableMap disjointUnion(Map first, Map second) {
    checkNotNull(first);
    checkNotNull(second);
    final ImmutableMap.Builder ret = ImmutableMap.builder();

    // will throw an exception if there is any null mapping
    ret.putAll(first);
    for (final Entry secondEntry : second.entrySet()) {
      final V firstForKey = first.get(secondEntry.getKey());
      if (firstForKey == null) {
        // non-duplicate
        // we know the first map doesn't actually map this key to null
        // or ret.putAll(first) above would fail
        ret.put(secondEntry.getKey(), secondEntry.getValue());
      } else if (firstForKey.equals(secondEntry.getValue())) {
        // duplicate. This is okay. Do nothing.
      } else {
        throw new RuntimeException("When attempting a disjoint map union, " +
            String.format("for key %s, first map had %s but second had %s", secondEntry.getKey(),
                firstForKey, secondEntry.getValue()));
      }
    }

    return ret.build();
  }

  /**
   * Creates a copy of the supplied map with its keys transformed by the supplied function, which
   * must be one-to-one on the keys of the original map. If two keys are mapped to the same value by
   * {@code injection}, an {@code IllegalArgumentException} is thrown.
   */
  public static  ImmutableMap copyWithKeysTransformedByInjection(
      final Map map, final Function injection) {
    final ImmutableMap.Builder ret = ImmutableMap.builder();
    for (final Map.Entry entry : map.entrySet()) {
      ret.put(injection.apply(entry.getKey()), entry.getValue());
    }
    return ret.build();
  }

  /**
   * Returns the length of the longest key in a map, or 0 if the map is empty. Useful for printing
   * tables, etc. The map may not have any null keys.
   */
  public static  int longestKeyLength(Map map) {
    if (map.isEmpty()) {
      return 0;
    }

    return Ordering.natural().max(
        FluentIterable.from(map.keySet())
            .transform(StringUtils.ToLength));
  }

  /**
   * Just like {@link com.google.common.base.Functions#forMap(Map, Object)} except it allows a
   * potentially non-constant {@link Function} as the default.
   */
  public static  Function asFunction(Map map,
      Function defaultFunction) {
    return new ForMapWithDefaultFunction(map, defaultFunction);
  }

  // indebted to Guava's Functions.forMap()
  private static class ForMapWithDefaultFunction implements Function {

    private final Map map;
    private final Function defaultFunction;

    private ForMapWithDefaultFunction(
        final Map map, final Function defaultFunction) {
      this.map = checkNotNull(map);
      this.defaultFunction = checkNotNull(defaultFunction);
    }

    @Override
    public V apply(final K input) {
      final V result = map.get(input);
      return (result != null || map.containsKey(result)) ? result : defaultFunction.apply(input);
    }

    @Override
    public int hashCode() {
      return Objects.hashCode(map, defaultFunction);
    }

    @Override
    public boolean equals(final Object obj) {
      if (this == obj) {
        return true;
      }
      if (obj == null || getClass() != obj.getClass()) {
        return false;
      }
      final ForMapWithDefaultFunction other = (ForMapWithDefaultFunction) obj;
      return Objects.equal(this.map, other.map)
          && Objects.equal(this.defaultFunction, other.defaultFunction);
    }

    @Override
    public String toString() {
      return "asFunction(" + map + ", default=" + defaultFunction + ")";
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy