/* * Copyright 2014 Goldman Sachs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gs.collections.impl; import java.util.Arrays; import com.gs.collections.api.RichIterable; import com.gs.collections.api.list.MutableList; import com.gs.collections.api.map.MutableMap; import com.gs.collections.impl.block.factory.Functions; import com.gs.collections.impl.block.factory.Procedures; import com.gs.collections.impl.factory.Lists; import com.gs.collections.impl.list.mutable.FastList; import com.gs.collections.impl.map.mutable.UnifiedMap; import com.gs.collections.impl.test.Verify; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class tests various algorithms for calculating anagrams from a list of words. */ public class AnagramTest { private static final Logger LOGGER = LoggerFactory.getLogger(AnagramTest.class); private static final int SIZE_THRESHOLD = 10; private MutableList<String> getWords() { return FastList.newListWith( "alerts", "alters", "artels", "estral", "laster", "ratels", "salter", "slater", "staler", "stelar", "talers", "least", "setal", "slate", "stale", "steal", "stela", "taels", "tales", "teals", "tesla"); } @Test public void anagramsWithMultimapInlined() { MutableList<RichIterable<String>> results = this.getWords() .groupBy(Alphagram::new) .multiValuesView() .select(iterable -> iterable.size() >= SIZE_THRESHOLD) .toSortedList(Functions.toIntComparator(RichIterable::size)); results.asReversed() .collect(iterable -> iterable.size() + ": " + iterable) .each(LOGGER::info); Verify.assertIterableSize(SIZE_THRESHOLD, results.getFirst()); } @Test public void anagramsWithMultimapGSCollections1() { MutableList<RichIterable<String>> results = this.getWords().groupBy(Alphagram::new) .multiValuesView() .select(iterable -> iterable.size() >= SIZE_THRESHOLD) .toSortedList(Functions.toIntComparator(iterable -> -iterable.size())); results.collect(iterable -> iterable.size() + ": " + iterable) .each(LOGGER::info); Verify.assertIterableSize(SIZE_THRESHOLD, results.getLast()); } private boolean listContainsTestGroupAtElementsOneOrTwo(MutableList<MutableList<String>> list) { return list.get(1).containsAll(this.getTestAnagramGroup()) || list.get(2).containsAll(this.getTestAnagramGroup()); } @Test public void anagramsWithMultimapGSCollections3() { MutableList<RichIterable<String>> results = this.getWords().groupBy(Alphagram::new) .multiValuesView() .toSortedList(Functions.toIntComparator(iterable -> -iterable.size())); results.collectIf(iterable -> iterable.size() >= SIZE_THRESHOLD, iterable -> iterable.size() + ": " + iterable) .each(LOGGER::info); Verify.assertIterableSize(SIZE_THRESHOLD, results.getLast()); } @Test public void anagramsWithMultimapGSCollections4() { MutableList<RichIterable<String>> results = this.getWords().groupBy(Alphagram::new) .multiValuesView() .toSortedList(Functions.toIntComparator(iterable -> -iterable.size())); results.forEach( Procedures.ifTrue( iterable -> iterable.size() >= SIZE_THRESHOLD, Functions.bind(Procedures.cast(LOGGER::info), iterable -> iterable.size() + ": " + iterable))); Verify.assertIterableSize(SIZE_THRESHOLD, results.getLast()); } @Test public void anagramsWithMultimapLazyIterable1() { MutableList<RichIterable<String>> results = this.getWords().groupBy(Alphagram::new) .multiValuesView() .toSortedList(Functions.toIntComparator(RichIterable::size)); results.asReversed() .collectIf(iterable -> iterable.size() >= SIZE_THRESHOLD, iterable -> iterable.size() + ": " + iterable) .forEach(Procedures.cast(LOGGER::info)); Verify.assertIterableSize(SIZE_THRESHOLD, results.getFirst()); } @Test public void anagramsWithMultimapForEachMultiValue() { MutableList<RichIterable<String>> results = Lists.mutable.of(); this.getWords().groupBy(Alphagram::new) .multiValuesView().forEach(Procedures.ifTrue(iterable -> iterable.size() >= SIZE_THRESHOLD, results::add)); results.sortThisByInt(iterable -> -iterable.size()) .forEach(Functions.bind(Procedures.cast(LOGGER::info), iterable -> iterable.size() + ": " + iterable)); Verify.assertIterableSize(SIZE_THRESHOLD, results.getLast()); } @Test public void anagramsUsingMapGetIfAbsentPutInsteadOfGroupBy() { MutableMap<Alphagram, MutableList<String>> map = UnifiedMap.newMap(); this.getWords().each(word -> map.getIfAbsentPut(new Alphagram(word), FastList::new).add(word)); MutableList<MutableList<String>> results = map.select(iterable -> iterable.size() >= SIZE_THRESHOLD, Lists.mutable.<MutableList<String>>of()) .sortThisByInt(iterable -> -iterable.size()); results.forEach(Functions.bind(Procedures.cast(LOGGER::info), iterable -> iterable.size() + ": " + iterable)); Assert.assertTrue(this.listContainsTestGroupAtElementsOneOrTwo(results)); Verify.assertSize(SIZE_THRESHOLD, results.getLast()); } private MutableList<String> getTestAnagramGroup() { return FastList.newListWith("least", "setal", "slate", "stale", "steal", "stela", "taels", "tales", "teals", "tesla"); } private static final class Alphagram { private final char[] key; private Alphagram(String string) { this.key = string.toCharArray(); Arrays.sort(this.key); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || this.getClass() != o.getClass()) { return false; } Alphagram alphagram = (Alphagram) o; return Arrays.equals(this.key, alphagram.key); } @Override public int hashCode() { return Arrays.hashCode(this.key); } @Override public String toString() { return new String(this.key); } } }