Get random value from a HashMap<String, HashSet<Integer>> - java

I have a function that accepts a HashMap<String, HashSet<Integer>>. Now I want to get a random value from the HashMap but I don't know how to do this. Could you give me a hint?
The output should consist of a tuple containing the String and an Integer value.

Knowing the size of the map, you could pick a random entry number, then iterate over the contents until you reach that entry. Example:
final Set<String> keys = allowedInput.keySet();
final int keyNumber = (int)(Math.random() * keys.size());
final Iterator<String> keyIterator = keys.iterator();
String randomKey = null;
for (int i = 0; i < keyNumber && keyIterator.hasNext(); i++) {
randomKey = keyIterator.next();
}
if (randomKey == null) {
// This should not happen unless the map was empty, or it was modified
// externally. Handle the potential error case accordingly.
}
final HashSet<Integer> value = allowedInput.get(randomKey);
// `value` now contains a random element from the `allowedInput` map.
If you want to retrieve a random Integer element from the resulting HashSet<Integer>, then you can adapt the same technique: simply pick a random element number based on the size of the set, and iterate over the contents until you find it.

If you want to repeatedly get random values, you could shuffle the set, and then go through it in order.
See Picking a random element from a set

I've created a generic solution that utilizes the answer of Mike and SecureRandom, and includes explicit null and bounds checking, as well as a quick return for singleton collections (not much to choose there).
public static <T> T getRandomElement(Collection<T> collection) {
if (collection == null || collection.isEmpty()) {
throw new IllegalArgumentException("Collection should not be null or empty");
}
if (collection.size() == 1) {
return collection.iterator().next();
}
// it would be beneficial to make this a field when used a lot
final Random random = new SecureRandom();
final int randomIndex = random.nextInt(collection.size());
// optimization for list instances, use optimized indexing
if (collection instanceof List) {
final List<T> list = (List<T>) collection;
return list.get(randomIndex);
}
int seen = 0;
for (T e : collection) {
if (seen++ == randomIndex) {
return e;
}
}
throw new IllegalStateException("Collection size was altered during operation");
}
Now you can simply retrieve a String and Integer by first selecting a key value from the key set, taking the value and choosing a random integer from that.
String key = getRandomElement(aMap.keySet());
Integer value = getRandomElement(aMap.get(key));

thx evry one for the help
i got i working now
this is the code i used
final Set<String> keys = allowedInput.keySet();
int keyNumber = (int)(random.nextInt(keys.size()));
final Iterator<String> keyIterator = keys.iterator();
String key = null;
for (int i = 0; i <= keyNumber; i++) {
key = keyIterator.next();
}
if (key == null) {
// handle empty map
}
HashSet<Integer> field = allowedInput.get(key);
final int fieldNumber = (int)(random.nextInt(field.size()));
int fieldID = 0;
int i = 0;
for(Object obj : field)
{
if (i == fieldNumber)
{
//fieldID = Integer.parseInt(obj.toString());
fieldID = (int)obj;
break;
}
i = i + 1;
}
// Start constructing the userinput
// Note: we need an instance of the UserInputSystem to create the UserInput instance!
UserInputSystem userInputSystem = new UserInputSystem();
UserInput input = userInputSystem.new UserInput(fieldID, key);
System.err.println("ai fieldID = "+fieldID+" key = "+key);

Related

Java Iterator Loop once, start in middle

I have an Iterator - placed somewhere in the middle of my collection.
I want to loop over the collection from there on, returning a special element if I find it.
If I reach !hasNext() then I want to start at the begining, but I want to stop if I reach the place where I started first.
The best Idea how to solve that seems currently to save the "first" (wherever the iterator pointed when I started) element and then stop if I find that one again.
And that works as long as items can occure only once in my collection (i.e. in a HasSet).
Any better ideas how to do such thing? Iterator doesn't seem to supply a pointer/number back to me that I could compare.
With Guava Iterators (Java 7):
Iterator<YourType> iterator = Iterators.concat(yourIteratorPlaceSomewhereInMiddle, Iterators.limit(yourCollection.iterator(), positionOfSomewhereInMiddle));
With Streams (Java 8):
Optional<YourType> theAnswer = IntStream.iterate(positionOfSomewhereInMiddle, pos -> ++pos)
.map(pos -> pos % sizeOfCollection)
.mapToObj(yourCollection::get)
.limit(sizeOfCollection)
.filter(element -> element is 42)
.findFirst();
If the collection is a list, then it can be done with below code
private void Object traverseList(List namesList, int startIndex ) {
int index = 0;
Iterator iterator = namesList.listIterator(startIndex);
while (iterator.hasNext() && index < namesList.size()){
Object element = iterator.next();
/*if(element.isSpecialElement()){
return element;
}
*/
index++;
System.out.println(element);
if(!iterator.hasNext()){
iterator = namesList.iterator();
}
}
}
Since you want to transverse all the elements in the list, I am making use of list size. And during iteration, if the special element is found, it can be returned.
To start to iterate a Set from a definedValue I do :
public void iterate(Set<Sample> set, Sample definedValue){
Iterator<Sample> iterator = set.iterator();
while(iterator.hasNext()){
Sample currentSample = iterator.next();
if(currentSample.equals(definedValue)){
while(iterator.hasNext()){
Sample sampleToConsider = iterator.next();
//Then do anything
}
}
}
}
The solution becomes more simple if you:
Don't use Iterator, it makes it more complicated
Use a List instead of Set as Set is ill-suited for this use case
public static void main(String[] args) {
Set<String> yourStartingCollection = new HashSet<>();
List<String> fooList = new ArrayList<>(yourStartingCollection);
Optional<String> specialElement = findSpecialElementStartingFromMiddle(fooList);
if (specialElement.isPresent()) {
// found it!
}
}
private static Optional<String> findSpecialElementStartingFromMiddle(List<String> elements) {
int middleIndex = elements.size() / 2;
Optional<String> result = Optional.empty();
for (int i = middleIndex; i < elements.size(); i++) {
String element = elements.get(i);
if (isSpecial(element)) {
result = Optional.of(element);
break;
}
}
if (result.isPresent()) {
return result;
}
for (int i = 0; i < middleIndex; i++) {
String element = elements.get(i);
if (isSpecial(element)) {
result = Optional.of(element);
break;
}
}
return result;
}
private static boolean isSpecial(String element) {
return element.equals("I'm special");
}

How to add an integer to a set while iterating?

I have a set of sets of integers: Set<Set<Integer>>.
I need to add integers to the set of sets as if it were a double array. So add(2,3) would have to add integer 3 to the 2nd set.
I know a set is not very suitable for this operation but it's not my call.
The commented line below clearly does not work but it shows the intention.
My question is how to add an integer to a set while iterating?
If it's necessary to identify each set, how would one do this?
#Override
public void add(int a, int b) {
if (!isValidPair(a, b)) {
throw new IllegalStateException("!isValidPair does not hold for (a,b)");
}
Iterator<Set<Integer>> it = relation.iterator();
int i = 0;
while (it.hasNext() && i <= a) {
//it.next().add(b);
i++;
}
}
One fundamental things you should be aware of, for which makes all existing answer in this question not working:
Once an object is added in a Set (similarly, as key in Map), it is not supposed to change (at least not in aspects that will change its equals() and hashCode()). The "Uniqueness" checking is done only when you add the object into the Set.
For example
Set<Set<Integer>> bigSet = new HashSet<>();
Set<Integer> v1 = new HashSet<>(Arrays.asList(1,2));
bigSet.add(v1);
System.out.println("contains " + bigSet.contains(new HashSet<>(Arrays.asList(1,2)))); // True
v1.add(3);
System.out.println("contains " + bigSet.contains(new HashSet<>(Arrays.asList(1,2)))); // False!!
System.out.println("contains " + bigSet.contains(new HashSet<>(Arrays.asList(1,2,3)))); // False!!
You can see how the set is corrupted. It contains a [1,2,3] but contains() does not work, neither for [1,2] nor [1,2,3].
Another fundamental thing is, your so-called '2nd set' may not make sense. Set implementation like HashSet maintain the values in arbitrary order.
So, with these in mind, what you may do is:
First find the n-th value, and remove it
add the value into the removed value set
re-add the value set.
Something like this (pseudo code again):
int i = 0;
Set<Integer> setToAdd = null;
for (Iterator itr = bigSet.iterator; itr.hasNext(); ++i) {
Set<Integer> s = itr.next();
if (i == inputIndex) {
// remove the set first
itr.remove();
setToAdd = s;
break;
}
}
// update the set and re-add it back
if (setToAdd != null) {
setToAdd.add(inputNumber);
bigSet.add(setToAdd);
}
Use a for-each loop and make your life easier.
public boolean add(int index, int value) {
// because a and b suck as variable names
if (index < 0 || index >= values.size()) {
return false;
}
int iter = 0;
for (Set<Integer> values : relation) {
if (iter++ == index) {
return values.add(value):
}
}
return false;
}
Now all you have to figure out is what to do if relation is unordered, as a Set or a relation are, because in that case a different Set<Integer> could match the same index each time the loop executes.
Use can use Iterators of Guava library like this :
#Override
public void add(int a, int b) {
if (!isValidPair(a, b)) {
throw new IllegalStateException("!isValidPair does not hold for (a,b)");
}
Iterators.get(relation.iterator(), a).add(b);
}
Edit : without Guava:
Iterator<Set<Integer>> iterator = relation.iterator();
for(int i = 0; i < a && iterator.hasNext(); ++i) {
iterator.next();
}
if(iterator.hasNext()) {
iterator.next().add(b);
}

How to create combinations of values in Java?

I have the following map: Map<Integer,String[]> map = new HashMap<Integer,String[]>();
The keys are integers and the values are arrays (could also be replaced by lists).
Now, I would like to get all possible combinations of the values among the keys. For example, let's say the map contains the following entries:
key 1: "test1", "stackoverflow"
key 2: "test2", "wow"
key 3: "new"
The combinations consists of
("test1","test2","new")
("test1","wow","new")
("stackoverflow", "test2", "new")
("stackoverflow", "wow", "new")
For this I imagine a method boolean hasNext() which returns true if there is a next pair and a second method which just returns the next set of values (if any).
How can this be done? The map could also be replaced by an other data structure.
The algorithm is essentially almost the same as the increment algorithm for decimal numbers ("x -> x+1").
Here the iterator class:
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.TreeSet;
public class CombinationsIterator implements Iterator<String[]> {
// Immutable fields
private final int combinationLength;
private final String[][] values;
private final int[] maxIndexes;
// Mutable fields
private final int[] currentIndexes;
private boolean hasNext;
public CombinationsIterator(final Map<Integer,String[]> map) {
combinationLength = map.size();
values = new String[combinationLength][];
maxIndexes = new int[combinationLength];
currentIndexes = new int[combinationLength];
if (combinationLength == 0) {
hasNext = false;
return;
}
hasNext = true;
// Reorganize the map to array.
// Map is not actually needed and would unnecessarily complicate the algorithm.
int valuesIndex = 0;
for (final int key : new TreeSet<>(map.keySet())) {
values[valuesIndex++] = map.get(key);
}
// Fill in the arrays of max indexes and current indexes.
for (int i = 0; i < combinationLength; ++i) {
if (values[i].length == 0) {
// Set hasNext to false if at least one of the value-arrays is empty.
// Stop the loop as the behavior of the iterator is already defined in this case:
// the iterator will just return no combinations.
hasNext = false;
return;
}
maxIndexes[i] = values[i].length - 1;
currentIndexes[i] = 0;
}
}
#Override
public boolean hasNext() {
return hasNext;
}
#Override
public String[] next() {
if (!hasNext) {
throw new NoSuchElementException("No more combinations are available");
}
final String[] combination = getCombinationByCurrentIndexes();
nextIndexesCombination();
return combination;
}
private String[] getCombinationByCurrentIndexes() {
final String[] combination = new String[combinationLength];
for (int i = 0; i < combinationLength; ++i) {
combination[i] = values[i][currentIndexes[i]];
}
return combination;
}
private void nextIndexesCombination() {
// A slightly modified "increment number by one" algorithm.
// This loop seems more natural, but it would return combinations in a different order than in your example:
// for (int i = 0; i < combinationLength; ++i) {
// This loop returns combinations in the order which matches your example:
for (int i = combinationLength - 1; i >= 0; --i) {
if (currentIndexes[i] < maxIndexes[i]) {
// Increment the current index
++currentIndexes[i];
return;
} else {
// Current index at max:
// reset it to zero and "carry" to the next index
currentIndexes[i] = 0;
}
}
// If we are here, then all current indexes are at max, and there are no more combinations
hasNext = false;
}
#Override
public void remove() {
throw new UnsupportedOperationException("Remove operation is not supported");
}
}
Here the sample usage:
final Map<Integer,String[]> map = new HashMap<Integer,String[]>();
map.put(1, new String[]{"test1", "stackoverflow"});
map.put(2, new String[]{"test2", "wow"});
map.put(3, new String[]{"new"});
final CombinationsIterator iterator = new CombinationsIterator(map);
while (iterator.hasNext()) {
System.out.println(
org.apache.commons.lang3.ArrayUtils.toString(iterator.next())
);
}
It prints exactly what's specified in your example.
P.S. The map is actually not needed; it could be replaced by a simple array of arrays (or list of lists). The constructor would then get a bit simpler:
public CombinationsIterator(final String[][] array) {
combinationLength = array.length;
values = array;
// ...
// Reorganize the map to array - THIS CAN BE REMOVED.
I took this as a challenge to see whether the new Java 8 APIs help with these kind of problems. So here's my solution for the problem:
public class CombinatorIterator implements Iterator<Collection<String>> {
private final String[][] arrays;
private final int[] indices;
private final int total;
private int counter;
public CombinatorIterator(Collection<String[]> input) {
arrays = input.toArray(new String[input.size()][]);
indices = new int[arrays.length];
total = Arrays.stream(arrays).mapToInt(arr -> arr.length)
.reduce((x, y) -> x * y).orElse(0);
counter = 0;
}
#Override
public boolean hasNext() {
return counter < total;
}
#Override
public Collection<String> next() {
List<String> nextValue = IntStream.range(0, arrays.length)
.mapToObj(i -> arrays[i][indices[i]]).collect(Collectors.toList());
//rolling carry over the indices
for (int j = 0;
j < arrays.length && ++indices[j] == arrays[j].length; j++) {
indices[j] = 0;
}
counter++;
return nextValue;
}
}
Note that I don't use a map as an input as the map keys actually don't play any role here. You can use map.values() though to pass in the input for the iterator. With the following test code:
List<String[]> input = Arrays.asList(
new String[] {"such", "nice", "question"},
new String[] {"much", "iterator"},
new String[] {"very", "wow"}
);
Iterator<Collection<String>> it = new CombinatorIterator(input);
it.forEachRemaining(System.out::println);
the output will be:
[such, much, very]
[nice, much, very]
[question, much, very]
[such, iterator, very]
[nice, iterator, very]
[question, iterator, very]
[such, much, wow]
[nice, much, wow]
[question, much, wow]
[such, iterator, wow]
[nice, iterator, wow]
[question, iterator, wow]

Is there a smart way to check if for each key in a hash table, they all have the same value?

Is there a smart way to check if all keys map to the same value? So the hash table will be as below:
a=>2;
b=>2;
c=>2;
d=>2;
So a,b,d,c and d all map to the same val. I am asking because I have to find the maximum occurrence of a number in a list but it no number is the clear max, I should just print "None". So if 2 number have the max, it means no number is the clear max in terms of occurrence. Also, how do I check if there's no clear max in the values.
Below is what I have so far but it always returns "None":
private static void getMaxOccrrance(String a) {
String[] sNew = a.split(",");
Hashtable<Integer,Integer> nums = new Hashtable<>();
for(String x : sNew) {
int num = Integer.parseInt(x);
if (!nums.containsKey(num)) {
nums.put(num, 1);
} else {
nums.put(num, nums.get(num) + 1);
}
}
int val = 0, max = 1;
for(int keys : nums.keySet()){
if(nums.get(keys) > max){
val = keys;
max = nums.get(keys);
}
}
boolean uniqueMax = true;
int count = 0;
for(int values : nums.values()){
if(val == values) {
count++;
if(count >= 2){
uniqueMax = false;
break;
}
}
}
if(uniqueMax){
System.out.println(val);
}else {
System.out.println("None");
}
}
If you work with Map in a single thread, much more efficient to keep&update this information directly on Map operations, if they are always non-decreasing by value put()s. E. g.
class MyMap<K> {
Map<K, Integer> impl;
K singleMaxKey;
int maxValue;
public void put(K key, int value) {
if (value > maxValue) {
maxValue = value;
singleMaxKey = key;
} else if (value == maxValue && !key.equals(singleMaxKey)) {
sibgleMaxKey = null;
}
impl.put(key, value);
}
}
If you have Java 8 you can do this fairly easily using streams. The following will return a map from each distinct value in a list to its frequency:
Map<Value, Integer> getFrequencyMap(Collection<Value> list) {
return list.stream().distinct()
.collect(Collectors.toMap(value -> value, value -> Collections.frequency(list, value));
}
You can call this with map.values() to get the frequency of all values in the your map.
If you wish to determine if there is more than one value that occurs the same, maximum number of times, you can check the new frequency map to see if the value occurs more than once:
Map<Key, Value> map;
Map<Value, Integer> valueFrequencies = getFrequencyMap(map.values());
int maxFrequency = valueFrequencies.values().stream().max().orElse(0);
if (Collections.frequency(valueFrequencies.values(), maxFrequency) > 1) {
// no clear max frequency
}

Is it possible to find out if a value exists twice in an arraylist?

I have an integer arraylist..
ArrayList <Integer> portList = new ArrayList();
I need to check if a specific integer has already been entered twice. Is this possible in Java?
You could use something like this to see how many times a specific value is there:
System.out.println(Collections.frequency(portList, 1));
// There can be whatever Integer, and I use 1, so you can understand
And to check if a specific value is there more than once you could use something like this:
if ( (Collections.frequency(portList, x)) > 1 ){
System.out.println(x + " is in portList more than once ");
}
My solution
public static boolean moreThanOnce(ArrayList<Integer> list, int searched)
{
int numCount = 0;
for (int thisNum : list) {
if (thisNum == searched)
numCount++;
}
return numCount > 1;
}
If you are looking to do this in one method, then no. However, you could do it in two steps if you need to simply find out if it exists at least more than once in the List. You could do
int first = list.indexOf(object)
int second = list.lastIndexOf(object)
// Don't forget to also check to see if either are -1, the value does not exist at all.
if (first == second) {
// No Duplicates of object appear in the list
} else {
// Duplicate exists
}
This will tell you if you have at least two same values in your ArrayList:
int first = portList.indexOf(someIntValue);
int last = portList.lastIndexOf(someIntValue);
if (first != -1 && first != last) {
// someIntValue exists more than once in the list (not sure how many times though)
}
If you really want to know how many duplicates of a given value you have, you need to iterate through the entire array. Something like this:
/**
* Will return a list of all indexes where the given value
* exists in the given array. The list will be empty if the
* given value does not exist at all.
*
* #param List<E> list
* #param E value
* #return List<Integer> a list of indexes in the list
*/
public <E> List<Integer> collectFrequency(List<E> list, E value) {
ArrayList<Integer> freqIndex = new ArrayList<Integer>();
E item;
for (int i=0, len=list.size(); i<len; i++) {
item = list.get(i);
if ((item == value) || (null != item && item.equals(value))) {
freqIndex.add(i);
}
}
return freqIndex;
}
if (!collectFrequency(portList, someIntValue).size() > 1) {
// Duplicate value
}
Or using the already availble method:
if (Collections.frequency(portList, someIntValue) > 1) {
// Duplicate value
}
Set portSet = new HashSet<Integer>();
portSet.addAll(portList);
boolean listContainsDuplicates = portSet.size() != portList.size();
I used the following solution to find out whether an ArrayList contains a number more than once. This solution comes very close to the one listed by user3690146, but it does not use a helper variable at all. After running it, you get "The number is listed more than once" as a return message.
public class Application {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(4);
list.add(8);
list.add(1);
list.add(8);
int number = 8;
if (NumberMoreThenOnceInArray(list, number)) {
System.out.println("The number is listed more than once");
} else {
System.out.println("The number is not listed more than once");
}
}
public static boolean NumberMoreThenOnceInArray(ArrayList<Integer> list, int whichNumber) {
int numberCounter = 0;
for (int number : list) {
if (number == whichNumber) {
numberCounter++;
}
}
if (numberCounter > 1) {
return true;
}
return false;
}
}
Here is my solution (in Kotlin):
// getItemsMoreThan(list, 2) -> [4.45, 333.45, 1.1, 4.45, 333.45, 2.05, 4.45, 333.45, 2.05, 4.45] -> {4.45=4, 333.45=3}
// getItemsMoreThan(list, 1)-> [4.45, 333.45, 1.1, 4.45, 333.45, 2.05, 4.45, 333.45, 2.05, 4.45] -> {4.45=4, 333.45=3, 2.05=2}
fun getItemsMoreThan(list: List<Any>, moreThan: Int): Map<Any, Int> {
val mapNumbersByElement: Map<Any, Int> = getHowOftenItemsInList(list)
val findItem = mapNumbersByElement.filter { it.value > moreThan }
return findItem
}
// Return(map) how often an items is list.
// E.g.: [16.44, 200.00, 200.00, 33.33, 200.00, 0.00] -> {16.44=1, 200.00=3, 33.33=1, 0.00=1}
fun getHowOftenItemsInList(list: List<Any>): Map<Any, Int> {
val mapNumbersByItem = list.groupingBy { it }.eachCount()
return mapNumbersByItem
}
By looking at the question, we need to find out whether a value exists twice in an ArrayList. So I believe that we can reduce the overhead of "going through the entire list just to check whether the value only exists twice" by doing the simple check below.
public boolean moreThanOneMatch(int number, ArrayList<Integer> list) {
int count = 0;
for (int num : list) {
if (num == number) {
count ++ ;
if (count == 2) {
return true;
}
}
}
return false;
}

Categories