/* * Copyright 2004-2016 EPAM Systems * * This file is part of JDI project. * * JDI is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * JDI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with JDI. If not, see <http://www.gnu.org/licenses/>. */ package com.epam.commons.map; import com.epam.commons.LinqUtils; import com.epam.commons.pairs.Pair; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Collectors; import static com.epam.commons.PrintUtils.print; import static com.epam.commons.TryCatchUtil.throwRuntimeException; import static java.util.stream.Collectors.toList; /** * Created by Roman_Iovlev on 6/3/2015. */ public class MapArray<K, V> implements Collection<Pair<K, V>>, Cloneable { public List<Pair<K, V>> pairs; public MapArray() { pairs = new CopyOnWriteArrayList<>(); } public MapArray(K key, V value) { this(); add(key, value); } public <T> MapArray(Collection<T> collection, Function<T, K> key, Function<T, V> value) { this(); for (T t : collection) add(key.apply(t), value.apply(t)); } public MapArray(Collection<K> collection, Function<K, V> value) { this(); for (K k : collection) add(k, value.apply(k)); } public <T> MapArray(T[] array, Function<T, K> key, Function<T, V> value) { this(); for (T t : array) add(key.apply(t), value.apply(t)); } public MapArray(K[] array, Function<K, V> value) { this(); for (K k : array) add(k, value.apply(k)); } public MapArray(int count, Function<Integer, K> key, Function<Integer, V> value) { this(); for (int i = 0; i < count; i++) add(key.apply(i), value.apply(i)); } public MapArray(MapArray<K, V> mapArray) { this(); addAll(mapArray.stream().collect(toList())); } public MapArray(Object[][] objects) { this(); add(objects); } public static <T> MapArray<Integer, T> toMapArray(Collection<T> collection) { MapArray<Integer, T> mapArray = new MapArray<>(); int i = 0; for (T t : collection) mapArray.add(i++, t); return mapArray; } public static <T> MapArray<Integer, T> toMapArray(T[] array) { Set<T> mySet = new HashSet<>(); Collections.addAll(mySet, array); return toMapArray(mySet); } public static <Key, Value> MapArray<Key, Value> toMapArray(Map<Key, Value> map) { MapArray<Key, Value> mapArray = new MapArray<>(); for (Map.Entry<Key, Value> e : map.entrySet()) mapArray.add(e.getKey(), e.getValue()); return mapArray; } public <KResult, VResult> MapArray<KResult, VResult> toMapArray( BiFunction<K, V, KResult> key, BiFunction<K, V, VResult> value) { MapArray<KResult, VResult> result = new MapArray<>(); for (Pair<K, V> pair : pairs) result.add(key.apply(pair.key, pair.value), value.apply(pair.key, pair.value)); return result; } public <VResult> MapArray<K, VResult> toMapArray(Function<V, VResult> value) { MapArray<K, VResult> result = new MapArray<>(); for (Pair<K, V> pair : pairs) result.add(pair.key, value.apply(pair.value)); return result; } public boolean add(K key, V value) { if (hasKey(key)) return false; pairs.add(new Pair<>(key, value)); return true; } public MapArray<K,V> update(K key, V value) { if (hasKey(key)) removeByKey(key); pairs.add(new Pair<>(key, value)); return this; } public MapArray<K,V> update(K key, Function<V, V> func) { V value = null; if (hasKey(key)) { value = get(key); removeByKey(key); } pairs.add(new Pair<>(key, func.apply(value))); return this; } public void add(Object[][] pairs) { for (Object[] pair : pairs) if (pair.length == 2) add((K) pair[0], (V) pair[1]); } public void addOrReplace(K key, V value) { if (hasKey(key)) removeByKey(key); add(key, value); } public void addOrReplace(Object[][] pairs) { for (Object[] pair : pairs) if (pair.length == 2) addOrReplace((K) pair[0], (V) pair[1]); } private boolean hasKey(K key) { return keys().contains(key); } public boolean addFirst(K key, V value) { if (hasKey(key)) return false; List<Pair<K, V>> result = new CopyOnWriteArrayList<>(); result.add(new Pair<>(key, value)); result.addAll(pairs); pairs = result; return true; } /* public V get(Object oKey) { K key = null; try { key = (K)oKey; } catch (Exception ex) { throwRuntimeException(new Exception("Can't do get in MapArray. Key have wrong type")); } return get(key); }*/ public V get(K key) { Pair<K, V> first = null; try { first = LinqUtils.first(pairs, pair -> pair.key.equals(key)); } catch (Exception ignore) { } return (first != null) ? first.value : null; } public Pair<K, V> get(int index) { if (index < 0) index = pairs.size() + index; if (index < 0) return null; return (pairs.size() > index) ? pairs.get(index) : null; } public Pair<K, V> getFromEnd(int index) { return get(size() - index - 1); } public K key(int index) { return get(index).key; } public V value(int index) { return get(index).value; } public Collection<K> keys() { return LinqUtils.select(pairs, pair -> pair.key); } public Collection<V> values() { return LinqUtils.select(pairs, pair -> pair.value); } public Collection<V> values(Function<V, Boolean> condition) { return LinqUtils.where(values(), condition); } public int size() { return pairs.size(); } public int count() { return size(); } public boolean isEmpty() { return size() == 0; } public boolean any() { return size() > 0; } public Pair<K, V> first() { return get(0); } public Pair<K, V> last() { return getFromEnd(0); } public MapArray<K, V> revert() { List<Pair<K, V>> result = new CopyOnWriteArrayList<>(); for (int i = size() - 1; i >= 0; i--) result.add(get(i)); pairs = result; return this; } public boolean contains(Object o) { return values().contains(o); } public Iterator<Pair<K, V>> iterator() { return pairs.iterator(); } public Object[] toArray() { return pairs.toArray(); } public <T> T[] toArray(T[] a) { return pairs.toArray(a); } public boolean add(Pair<K, V> kv) { return pairs.add(kv); } /* public V remove(Object key) { boolean isRemoved = false; for (Object kv : pairs) if (kv.equals(key)) { V value = ((Pair<K,V>)kv).value; pairs.remove(kv); return value; } return null; }*/ public boolean remove(Object o) { boolean isRemoved = false; for (Object kv : pairs) if (kv.equals(o)) { pairs.remove(kv); isRemoved = true; } return isRemoved; } public void removeByKey(K key) { pairs.remove(LinqUtils.firstIndex(pairs, pair -> pair.key.equals(key))); } public void removeAllValues(V value) { LinqUtils.where(pairs, p -> p.value.equals(value)).forEach(pairs::remove); } public boolean containsAll(Collection<?> c) { for (Object o : c) if (!contains(o)) return false; return true; } public boolean addAll(Collection<? extends Pair<K, V>> c) { for (Pair<K, V> pair : c) add(pair); return true; } public boolean removeAll(Collection<?> c) { for (Object o : c) if (!remove(o)) return false; return true; } public boolean retainAll(Collection<?> c) { for (Pair pair : pairs) if (!c.contains(pair)) if (!remove(pair)) return false; return true; } public void clear() { pairs.clear(); } @Override public String toString() { return print(LinqUtils.select(pairs, pair -> pair.key + ":" + pair.value)); } @Override public MapArray<K, V> clone() { return new MapArray<>(this); } public MapArray<K, V> copy() { return clone(); } public <T1> List<T1> select(BiFunction<K, V, T1> func) { try { return pairs.stream() .map(pair -> func.apply(pair.key, pair.value)) .collect(toList()); } catch (Exception ignore) { throwRuntimeException(ignore); return new ArrayList<>(); } } public MapArray<K, V> where(BiFunction<K, V, Boolean> func) { try { return pairs.stream().filter(pair -> func.apply(pair.key, pair.value)) .collect(Collectors.toCollection(MapArray::new)); } catch (Exception ignore) { throwRuntimeException(ignore); return null; } } public V first(BiFunction<K, V, Boolean> func) { try { for (Pair<K, V> pair : pairs) if (func.apply(pair.key, pair.value)) return pair.value; return null; } catch (Exception ignore) { throwRuntimeException(ignore); return null; } } public void foreach(BiConsumer<K, V> action) { try { for (Pair<K, V> pair : pairs) action.accept(pair.key, pair.value); } catch (Exception ignore) { throwRuntimeException(ignore); } } public <R> List<R> selectMany(BiFunction<K, V, List<R>> func) { try { List<R> result = new ArrayList<>(); for (Pair<K, V> pair : pairs) result.addAll(func.apply(pair.key, pair.value)); return result; } catch (Exception ignore) { throwRuntimeException(ignore); return null; } } }