I'm writing a Java program in which I want to sort a set of items and get the N-highest elements of the set. The thing is, though, that I want the elements to be returned grouped by their rank -- so if I want the 3 highest elements, but there is a tie between two elements for third place, then the third result is a collection that contains the two tied elements.
I know I could write this myself, but I'm wondering if it's already been implemented somewhere else. Does anybody know of anything like this?
Sounds like the Google Collection's MultiMap might be what you're after.
Use the "rank" as your key when inserting your elements. Then sort the keys.
This is what I ended up going with:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.google.common.collect.Ordering;
public final class Sorting {
private Sorting() {}
public static <T extends Comparable<? super T>> List<List<T>> rank(
Iterable<T> iterable, int nRanks) {
if (nRanks < 0) {
throw new IllegalArgumentException(Integer.toString(nRanks));
}
if (nRanks == 0) {
return new ArrayList<List<T>>();
}
Iterator<T> iter = Ordering.natural().sortedCopy(iterable).iterator();
List<List<T>> ret = new ArrayList<List<T>>();
if (iter.hasNext()) {
T prev = iter.next();
List<T> group = new ArrayList<T>();
group.add(prev);
ret.add(group);
int rank = 1;
while (iter.hasNext()) {
T next = iter.next();
if (prev.compareTo(next) > 0) {
rank++;
if (rank > nRanks) {
break;
}
group = new ArrayList<T>();
ret.add(group);
}
group.add(next);
prev = next;
}
}
return ret;
}
}
Related
I struggle with generating all possible combinations of values of a List of Attributes. As an example, for three attributes A, B,C, with the following values:{a1,a2} for A ,{b1,b2} for B, and {c1,c2} for C, I should get 8 combinations:
a1,b1,c1
a1,b1,c2
a1,b2,c1
a1,b2,c2
a2,b1,c1
a2,b1,c2
a2,b2,c1
a2,b2,c2
I used the following two recursive java functions where attribute_to_domain is a Map where we put each attribute as a key and its values as a value, and we add each combination as an <ArrayList<String> toenumerate_tuples as an ArrayList<ArrayList<String>>
public void fillTuples(Map<String, Set<String>> attribute_to_domain, ArrayList<String> attributes, ArrayList<ArrayList<String>> enumerate_tuples)
{
for (Map.Entry<String, Set<String>> entrySet :attribute_to_domain.entrySet()) {
String attribute=entrySet.getKey();
attributes.add(attribute);
}
int pos = 0;
Set<String> domain = attribute_to_domain.get(attributes.get(pos));
for (Iterator<String> it = domain.iterator(); it.hasNext();) {
String val = it.next();
ArrayList<String> tuple=new ArrayList<String>();
tuple.add(val);
fillTuples(attribute_to_domain, attributes, 1, tuple, enumerate_tuples);
tuple.remove(tuple.size()-1);
assert(tuple.isEmpty());
}
}
public void fillTuples(Map<String, Set<String>> attribute_to_domain, ArrayList<String> attributes, int pos, ArrayList<String> tuple, ArrayList<ArrayList<String>> enumerate_tuples)
{
assert(tuple.size() == pos);
if (pos == attributes.size())
{
enumerate_tuples.add(tuple);
return;
}
Set<String> domain = attribute_to_domain.get(attributes.get(pos));
for (Iterator<String> it = domain.iterator(); it.hasNext();) {
String val = it.next();
tuple.add(val);
fillTuples(attribute_to_domain, attributes, pos+1, tuple, enumerate_tuples);
tuple.remove(tuple.size()-1);
}
}
The problem that I get enumerate_tuples with empty elements and I can not keep changes that happened on it through the calls.
How can I solve this problem, please? Thanks in advance.
There is a simpler and faster solution, one that does not require recursion.
The number of output combinations can be calculated in advanced: multiplication of attributes in your case 2*2*2 but it is true for every combination.
Furthermore, we can calculate which value will be placed in each combination based on the combination index. if we assume combination index goes from 0 to 7:
for A:
- combinations 0-3 will contain a1
- combinations 4-7 will contain a2
for B
- combinations 0,1,4,5 will contain b1
- combinations 2,3,6,7 will contain b2
for C
- combinations 0,2,4,6 will contain c1
- combinations 1,3,5,7 will contain c2
so the formula for value placement is based on the combination index, the order of the attributes (A first etc) and the order of the values in the attribute.
the complexity of this algorithm is o(n*m) where n is number of attributes and m number of values.
Revised from Cartesian product of arbitrary sets in Java
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
public class CartesianProduct {
public static Set<Set<Object> > cartesianProduct(Set<?>... sets) {
if (sets.length < 2)
throw new IllegalArgumentException(
"Can't have a product of fewer than two sets (got " +
sets.length + ")");
return _cartesianProduct(0, sets);
}
private static Set<Set<Object> > _cartesianProduct(int index, Set<?>... sets) {
Set<Set<Object> > ret = new TreeSet<Set<Object> >(new Comparator<Set<Object> >() {
#Override
public int compare(Set<Object> o1, Set<Object> o2) {
return o1.toString().compareTo(o2.toString());
}
});
if (index == sets.length) {
ret.add(new TreeSet<Object>());
} else {
for (Object obj : sets[index]) {
for (Set<Object> set : _cartesianProduct(index+1, sets)) {
set.add(obj);
ret.add(set);
}
}
}
return ret;
}
public static void main(String[] args) {
Map<String, Set<String> > dataMap = new HashMap<String, Set<String> >();
dataMap.put("A", new TreeSet<String>(Arrays.asList("a1", "a2")));
dataMap.put("B", new TreeSet<String>(Arrays.asList("b1", "b2")));
dataMap.put("C", new TreeSet<String>(Arrays.asList("c1", "c2")));
System.out.println(cartesianProduct(dataMap.values().toArray(new Set<?>[0])));
}
}
I'm trying to implement a sorting for Generics in Java.
Here is the abstract class Function (T is my "key" in order to sort):
public abstract class Function<T extends Comparable<T>, S> {
abstract public T compute(S o);
}
Here is class Applier, whose method "apply" sorts the list according on the result of "compute":
import java.util.ArrayList;
import java.util.Iterator;
public class Applier<T extends Comparable<T>, S> {
ArrayList<S> apply(ArrayList<S> input, Function<T, S> function) {
ArrayList<T> output = new ArrayList<>();
for(Iterator<S> it = input.iterator(); it.hasNext(); ){
output.add(function.compute(it.next()));
}
T tmpTi, tmpTj;
S tmpSi, tmpSj;
for(int i=0; i<input.size(); i++) {
for(int j=i+1; j<input.size(); j++) {
if(output.get(i).compareTo(output.get(j))>0) {
tmpTi = output.get(i);
tmpTj = output.get(j);
output.remove(j);
output.remove(i);
output.add(i, tmpTi);
output.add(i, tmpTj);
tmpSi = input.get(i);
tmpSj = input.get(j);
input.remove(j);
input.remove(i);
input.add(i, tmpSj);
input.add(j, tmpSi);
}
}
}
return input;
}
}
My question is: is there a smarter way to do this sorting, maybe not with a bubblesort?
Here is also the main class:
public static void main(String[] args) {
Applier a = new Applier<>();
StringLength strlen = new StringLength();
ArrayList<String> array = new ArrayList<>();
array.add("Hola");
array.add("Man");
array.add("randomstufff");
array.add("Zerrone");
array.add("Info3a");
System.out.println("Order by length");
System.out.print("before: ");
System.out.println(array);
a.apply(array, strlen); //works on original object
System.out.print("After: ");
System.out.println(array);
Basically you want to sort an array based on some other array. You will be able to use Collections.sort if you introduce a wrapper object that contains both the values and the function results, and sort that one.
Here's a solution using Java 8 streaming API:
public class Applier<T extends Comparable<T>, S> {
static class Wrapper<T extends Comparable<T>,S> implements Comparable<Wrapper<T,S>> {
T key;
S value;
Wrapper(S s, Function<T, S> function) {
this.key = function.compute(s);
this.value = s;
}
public int compareTo(Wrapper<T,S> that) {
return key.compareTo(that.key);
}
}
ArrayList<S> apply(ArrayList<S> input, Function<T, S> function) {
S[] sorted = (S[]) IntStream.range(0, input.size())
.mapToObj(i -> new Wrapper<T,S>(input.get(i), function))
.sorted()
.map(b -> b.value).toArray();
input.clear();
input.addAll(Arrays.asList(sorted));
return input;
}
}
Note that there's an error in the way you swap elements in your Bubble Sort: When re-inserting the elements into output, you misplaced i and j. Also, instead of removing and re-inserting the elements, just use set(index, element) to overwrite the previous entry.
Also, instead of using two lists and keeping those lists in synch, better just use a Map.
public static class Applier<T extends Comparable<T>, S> {
ArrayList<S> apply(ArrayList<S> input, Function<T, S> function) {
Map<S, T> compareBy = new HashMap<>();
for (S s : input) {
compareBy.put(s, function.compute(s));
}
for(int i=0; i<input.size(); i++) {
for(int j=i+1; j<input.size(); j++) {
if (compareBy.get(input.get(i)).compareTo(compareBy.get(input.get(j))) > 0) {
S tmpS = input.get(j);
input.set(j, input.get(i));
input.set(i, tmpS);
}
}
}
return input;
}
}
And of course, sorting is already implemented in Java. So other than for learning how to code, you should always use the builtin functions. In Java 8, it's just a single line:
Collections.sort(array, Comparator.comparing(String::length));
Note, however, that Comparator.comparing will call the comparator function for each pairwise comparison (i.e. on the order of 2nlogn times for a decent sorting algorithm). If that function is computationally very expensive, you might want to cache it yourself, using a Map.
Map<String, Integer> compareBy = array.stream().collect(Collectors.toMap(s -> s, s -> s.length()));
Collections.sort(array, Comparator.comparing((String s) -> compareBy.get(s)));
I was asked the following question in an interview:
Combine two iterators over their sorted contents such that the
resulting iterator should iterate over the combination of these 2
iterators in sorted order in O(1) time (these iterators iterate over a
String).
I wrote the below code but I'm sure it doesn't perform in O(1) time. What advice do you have for matching the constraints set by the interview question?
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class iteratorCombine {
// assumption1: elements are hardcoded
// assumption2: both iterators have equal number of elements
public static void main(String[] args) {
iteratorCombine testObj = new iteratorCombine();
Set<String> firstSet = new TreeSet<String>();
Set<String> secondSet = new TreeSet<String>();
Set<String> combinedSet;
firstSet = testObj.storeElements1(firstSet);
secondSet = testObj.storeElements2(secondSet);
Iterator<String> it1 = firstSet.iterator();
Iterator<String> it2 = secondSet.iterator();
combinedSet = testObj.combine(it1, it2);
// output
Iterator<String> itComb = combinedSet.iterator();
while(itComb.hasNext()){
System.out.println(itComb.next());
}
}
public Set<String> storeElements1(Set<String> firstSet){
firstSet.add("first3");
firstSet.add("first1");
firstSet.add("first2");
return firstSet;
}
public Set<String> storeElements2(Set<String> secondSet){
secondSet.add("second3");
secondSet.add("second1");
secondSet.add("second2");
return secondSet;
}
public Set<String> combine(Iterator<String> it1, Iterator<String>it2){
String firstEle, secondEle;
Set<String> combinedSet = new TreeSet<String>();
while (it1.hasNext() && it2.hasNext()) {
firstEle = it1.next();
secondEle = it2.next();
combinedSet.add(firstEle+secondEle);
}
return combinedSet;
}
}
I believe that you can't do it if you don't extend iterator and support a peek function. Such an iterator is not that hard. Here is a way for doing it.
static class PeekingIterator<T> implements Iterator<T> {
private final Iterator<T> iterator;
private T temp;
public PeekingIterator(Iterator<T> iterator) {
this.iterator = iterator;
}
public T peek() {
//if there is no peek, advance the iterator and store its value, return the peek otherwise
if(temp==null){
temp = this.iterator.next();
}
return temp;
}
#Override
public T next() {
//if we already have a peek,return it and nullify it, otherwise do normal next()
if(temp!=null){
T t = temp;
temp = null;
return t;
}else{
return this.iterator.next();
}
}
#Override
public boolean hasNext() {
return this.iterator.hasNext() || temp!=null;
}
}
Once you can peek, the rest is easy, you can build SortedIterator using two peeking iterators, peek both iterators and advance the iterator that has the smaller element.
static class SortedIterator<T extends Comparable<T>> implements Iterator<T>{
private final PeekingIterator<T> peekingIterator1;
private final PeekingIterator<T> peekingIterator2;
SortedIterator(Iterator<T> source1, Iterator<T> source2){
peekingIterator1 = new PeekingIterator<>(source1);
peekingIterator2 = new PeekingIterator<>(source2);
}
#Override
public boolean hasNext() {
return peekingIterator1.hasNext() || peekingIterator2.hasNext();
}
#Override
public T next() {
if(!peekingIterator1.hasNext()){
return peekingIterator2.next();
}
if(!peekingIterator2.hasNext()){
return peekingIterator1.next();
}
T peek1 = peekingIterator1.peek();
T peek2 = peekingIterator2.peek();
if(peek1.compareTo(peek2)<0){
return peekingIterator1.next();
}
return peekingIterator2.next();
}
}
The analysis are obvious here, SortedIterator.next and SortedIterator.hasNext run in constant time.
I had a similar use case but instead of only 2 iterators, I had to merge a dynamic number of iterators. The number of iterators can be more than 2. e.g., 3 iterators, 4 iterators, or more.
I used the same solution as Sleiman Jneidi suggested. I modified the SortedIterator to support multiple iterators and also support sorting in ascending or descending order based on need.
For the PeekingIterator, I used Apache commons collection's Peeking iterator.
Here is my sorted iterator if someone may need to merge multiple sorted iterators, they can refer to this:
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.commons.collections4.iterators.PeekingIterator;
/**
* This class is special implementation of Iterator.
* It lets multiple sorted iterators to be merged to a single sorted iterator.
* It will use given comparator to compare values from multiple iterators.
*
*/
public class SortedMergedIterator<T> implements Iterator<T> {
/**
* Comparator that will be used to compare values from across the iterators.
*/
private final Comparator<? super T> comparator;
/**
* List of sorted iterators which are required to be merged to a single sorted iterator.
*/
private final List<PeekingIterator<T>> peekingIterators;
/**
* By default the sort order will be considered as ascending order.
*
* It this flag is set to true, the elements will be sorted in descending order.
* In this case, it is pre-requisite that all the iterators being passed should be sorted in ascending order.
*/
private final boolean sortOrderDescending;
public SortedMergedIterator(final Comparator<? super T> comparator, final List<Iterator<T>> iterators) {
this(comparator, iterators, false);
}
public SortedMergedIterator(final Comparator<? super T> comparator, final List<Iterator<T>> iterators, final boolean sortOrderDescending) {
this.comparator = comparator;
this.peekingIterators = iterators.stream().map(iterator -> new PeekingIterator<>(iterator)).collect(Collectors.toList());
this.sortOrderDescending = sortOrderDescending;
}
#Override
public boolean hasNext() {
// If at least one of the child iterator has next element.
return this.peekingIterators.stream().anyMatch(Iterator::hasNext);
}
#Override
public T next() {
// Peek next value from all the iterators.
final List<T> peekedValues = this.peekingIterators.stream().map(PeekingIterator::peek).collect(Collectors.toList());
// Find the minimum value from all the peeked values.
final T minElement = peekedValues
.stream()
.filter(Objects::nonNull)
.min(this.sortOrderDescending ? this.comparator.reversed() : this.comparator)
.orElse(null);
// Return the next element from an iterator for which minimum value is found.
return this.peekingIterators.get(peekedValues.indexOf(minElement)).next();
}
}
Example of using this iterator:
public static void main(String[] args) {
// Example of ascending order sorted iterators.
final List<Integer> list1 = Lists.newArrayList(4,7,11,12,16);
final List<Integer> list2 = Lists.newArrayList(1,3,5,10,15);
final List<Integer> list3 = Lists.newArrayList(6,8,13,18,20);
final List<Integer> list4 = Lists.newArrayList(2,9,14,17,19);
final SortedMergedIterator<Integer> sortedIterator =
new SortedMergedIterator<>(Comparator.comparingInt(a -> a), Arrays.asList(list1.iterator(), list2.iterator(), list3.iterator(), list4.iterator()));
while (sortedIterator.hasNext()) {
System.out.println(sortedIterator.next());
}
System.out.println();
// Example of descending order sorted iterators.
final List<Integer> list5 = Lists.newArrayList(16,12,11,7,4);
final List<Integer> list6 = Lists.newArrayList(15,10,5,3,1);
final List<Integer> list7 = Lists.newArrayList(20,18,13,8,6);
final List<Integer> list8 = Lists.newArrayList(19,17,14,9,2);
final SortedMergedIterator<Integer> descSortedIterator =
new SortedMergedIterator<>(Comparator.comparingInt(a -> a), Arrays.asList(list5.iterator(), list6.iterator(), list7.iterator(), list8.iterator()), true);
while (descSortedIterator.hasNext()) {
System.out.println(descSortedIterator.next());
}
}
I have a vector in which which holds items of type string. i am able to add items to the vector using
public void AddItem(String value)
{
data[length] = value;
length++;
}
however i would like the vector to be sorted in ascending order once items are added to in any particular order for instance if i added these items
v.AddItem("10");
v.AddItem("20");
v.AddItem("30");
v.AddItem("40");
v.AddItem("50");
v.AddItem("90");
v.AddItem("70");
v.AddItem("80");
i would expect "90" to be the last item in the list. i tried using this
for (int i = length- 1; i>1;i++)
{
if (data[length -1].compareTo(data[length]) > 0)
{
data[length-1] = temp;
data[length]=data[length -1];
temp = data[length];
}
}
and it doesnt seem to work can anybody point me in the right direction?
Arrays.sort(data);
instead of
for (int i = length- 1; i>1;i++)
{
if (data[length -1].compareTo(data[length]) > 0)
{
data[length-1] = temp;
data[length]=data[length -1];
temp = data[length];
}
}
but recommend use collections, if random access - ArraysList, for example,
if consistent access to elements use LinkedList
List<YourType> list = new LinkedList<YourType>();
list.add(SomeValue);
Collections.sort(list);
If values distinct, you can use TreeSet, this Collection sort values when adding new value:
Set<YourType> set = new TreeSet<YourType>();
set.add(SomeValue);
// Collections.sort(list) - not needed, set already sorted :)
You can use Arrays.sort() (notice that you need to add import statement):
import java.util.Arrays; // or just: import java.util.*;
public void AddItem(String value)
{
data[length] = value;
length++;
Arrays.sort(data);
}
As other people have pointed out in the comments, the data structure you use is array, not Vector.
I have some Maps which I would like to calculate the cartesian product of. Can someone please suggest a good algorithm:
Data:
Key1 {100,101,102}
Key2 {200,201}
Key3 {300}
Required Output: (Order does matter)
100,200,300
101,200,300
102,200,300
100,201,300
101,201,300
102,201,300
Map is dynamic so Key and values can vary in size.
Thanks.
You will want to switch to using a LinkedHashMap so that order is preserved when you're iterating over keys.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class CartesianPrint {
public static void main(String[] args) {
Map<Integer,List<Integer>> groupMap = new LinkedHashMap<Integer,List<Integer>>();
groupMap.put(1,Arrays.asList(new Integer[]{100,101,102}));
groupMap.put(2,Arrays.asList(new Integer[]{200,201}));
groupMap.put(3,Arrays.asList(new Integer[]{300}));
List<List<Integer>> values = new ArrayList<List<Integer>>(groupMap.values());
int[] printList = new int[values.size()];
print(values,printList,values.size()-1);
}
static void print(List<List<Integer>> values, int[] printList, int level){
for (Integer value: values.get(level)) {
printList[level] = value;
if(level == 0){
System.out.println(Arrays.toString(printList));
}else{
print(values,printList,level-1);
}
}
}
}
Same as Ondra Žižka, if you don't need a map, take a List it works the same way.
Here is a not so optimized way (I should clone instead of recalculating product in recursion. But the idea is still here and its pretty short. I took special care to keep correct order, that's why I run through List backwards.
public static List<List<Integer>> getCart(List<List<Integer>> a_list) {
List<List<Integer>> l_result = new ArrayList<List<Integer>>();
if (a_list == null || a_list.isEmpty()) {
l_result.add(new ArrayList<Integer>());
return l_result;
}
for (Integer l_value : a_list.get(a_list.size()-1)) {
List<List<Integer>> l_resultPortion = getCart(a_list.subList(0, a_list.size() - 1));
for (List<Integer> l_list : l_resultPortion) {
l_list.add(l_value);
}
l_result.addAll(l_resultPortion);
}
return l_result;
}
I suggest to create a store of tuples (triplet in your example).
List<List<Integer>> store = new LinkedList();
Then create a Stack of numbers.
Stack<Integer> stack = new Stack();
Then write a recursive function:
In each recursive function call, push the actually processed value of the array into the stack, and add the current tuple to the store.
private static process( Iterator<String> keys ){
// Bottom-most key
if( ! keys.hasNext() ){
// Construct the tuple from the stack and add it to store.
}
else {
String currentKey = keys.next();
List<Integer> numbers = map.get( currentKey );
for( int i : numbers ){
stack.push( i );
process ( keys );
stack.pop(); // Dispose processed number.
}
}
}
I hope I figured out the problem right (no guarantee).
Sorry for not implementing it whole but that's your homework :)