ricknroll88
ricknroll88

Reputation: 39

Join two collections and get a random element

I need to join two Collection<String>, get n random elements and remove them from the original collection in which they are stored.

To join the collections I thought about iterate them and store in an custom map structure in a way to:

  1. have the same key stored n times
  2. get the original collection.

Is there a simple method to do that?

Can you help me?

Upvotes: 0

Views: 178

Answers (3)

Sean Landsman
Sean Landsman

Reputation: 7179

How about this:

Collection<String> collection1 = new ArrayList<String>();
Collection<String> collection2 = new ArrayList<String>();

List<String> allElements = new ArrayList<String>(collection1);
allElements.addAll(collection2);
Collections.shuffle(allElements);

Random random = new Random();
int n = 10;
List<String> randomResults = new ArrayList<String>(n);
for (int i = 0; i < n && !allElements.isEmpty(); i++) {
  String randomElement = allElements.remove(random.nextInt(allElements.size()));
  randomResults.add(randomElement);
}

collection1.removeAll(randomResults);
collection2.removeAll(randomResults);

Upvotes: 1

anthonyms
anthonyms

Reputation: 948

Does the following work for you?

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;

import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

public class Combiner {
    private static final Random rnd = new Random();

    public static void main(String[] args) {
        Collection<String> boys = Sets.newHashSet("James", "John", "andrew",
                "peter");
        Collection<String> girls = Sets.newHashSet("mary", "jane", "rose",
                "danny");

        // Combine the two
        Iterable<String> humans = Iterables.concat(boys, girls);

        // Get n Random elements from the mix
        int n = 2;
        Collection<String> removed = randomSample4(humans, n);

        // Remove from the original Collections
        Iterables.removeAll(boys, removed);
        Iterables.removeAll(girls, removed);

        // or even
        boys.removeAll(removed);
        girls.removeAll(removed);

        // And now we check if all is well
        System.out.println(boys);
        System.out.println(girls);

    }

    public static <T> Collection<T> randomSample4(Iterable<T> humans, int m) {
        List<T> sample = Lists.newArrayList(humans);
        Set<T> res = new HashSet<T>(m);
        int n = sample.size();
        for (int i = n - m; i < n; i++) {
            int pos = rnd.nextInt(i + 1);
            T item = sample.get(pos);
            if (res.contains(item))
                res.add(sample.get(i));
            else
                res.add(item);
        }
        return res;
    }
}

The randomSample4 method has been copied from this blog.

Upvotes: 0

Mechkov
Mechkov

Reputation: 4324

Interesting you want to use the map for that. I would suggest using a MultiMap (Google's Guava for example). It allows you to hold a key and then a Collection of values, all belonging to that key. So, you would have only two keys (corresponding to your original Collections).

Another solution would be to just add all Collections into a third a Collection (there is an addAll(Collection c) method available). Provided, there are no duplicate values, you can check if a certain item from the third collection is part of any of your other two while iterating.

These are kind of rudimentary ways to achieve whatever your question asked, but worth a try.

Hope these pointers help a bit!

Upvotes: 0

Related Questions