/* * Joinery -- Data frames for Java * Copyright (c) 2014, 2015 IBM Corp. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package joinery.impl; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import joinery.DataFrame; import joinery.DataFrame.RowFunction; public class Index { private final Map<Object, Integer> index; public Index() { this(Collections.<Object>emptyList()); } public Index(final Collection<?> names) { this(names, names.size()); } public Index(final Collection<?> names, final int size) { index = new LinkedHashMap<>(names.size()); final Iterator<?> it = names.iterator(); for (int i = 0; i < size; i++) { final Object name = it.hasNext() ? it.next() : i; add(name, i); } } public void add(final Object name, final Integer value) { if (index.put(name, value) != null) { throw new IllegalArgumentException("duplicate name '" + name + "' in index"); } } public void extend(final Integer size) { for (int i = index.size(); i < size; i++) { add(i, i); } } public void set(final Object name, final Integer value) { index.put(name, value); } public Integer get(final Object name) { final Integer i = index.get(name); if (i == null) { throw new IllegalArgumentException("name '" + name + "' not in index"); } return i; } public void rename(final Map<Object, Object> names) { final Map<Object, Integer> idx = new LinkedHashMap<>(); for (final Map.Entry<Object, Integer> entry : index.entrySet()) { final Object col = entry.getKey(); if (names.keySet().contains(col)) { idx.put(names.get(col), entry.getValue()); } else { idx.put(col, entry.getValue()); } } // clear and add all names back to preserve insertion order index.clear(); index.putAll(idx); } public Set<Object> names() { return index.keySet(); } public Integer[] indices(final Object[] names) { return indices(Arrays.asList(names)); } public Integer[] indices(final List<Object> names) { final int size = names.size(); final Integer[] indices = new Integer[size]; for (int i = 0; i < size; i++) { indices[i] = get(names.get(i)); } return indices; } public static <V> DataFrame<V> reindex(final DataFrame<V> df, final Integer ... cols) { return new DataFrame<V>( df.transform( cols.length == 1 ? new RowFunction<V, Object>() { @Override public List<List<Object>> apply(final List<V> values) { return Collections.<List<Object>>singletonList( Collections.<Object>singletonList( values.get(cols[0]) ) ); } } : new RowFunction<V, Object>() { @Override public List<List<Object>> apply(final List<V> values) { final List<Object> key = new ArrayList<>(cols.length); for (final int c : cols) { key.add(values.get(c)); } return Collections.<List<Object>>singletonList( Collections.<Object>singletonList( Collections.unmodifiableList(key) ) ); } } ).col(0), df.columns(), new Views.ListView<V>(df, false) ); } public static <V> DataFrame<V> reset(final DataFrame<V> df) { final List<Object> index = new ArrayList<>(df.length()); for (int i = 0; i < df.length(); i++) { index.add(i); } return new DataFrame<V>( index, df.columns(), new Views.ListView<V>(df, false) ); } }