Random Presentation Topic Picker returns null - java

Today my teacher asked me to program a random presentation topic picker for him.
The idea was, that the student goes to the pc and clicks on the message Dialog which then randomly generates a number between 1 and the max index of the topics and then prints the according topic.
I tried it with HashMaps. to put in the key that stays with the String together so that I can then (after the output) remove that entry so that no other student can get the same topic.
But it always returns at least 1 empty reference -> null.
Here is the code:
static HashMap<Integer, String> map = new HashMap<>();
public static void main(String[] args){
int anzahlEintraege = Integer.parseInt(JOptionPane.showInputDialog("Wie viele Themen gibt es?"));
for(int i = 0; i < anzahlEintraege; i++){
map.put((i+1),JOptionPane.showInputDialog("Geben Sie das Thema Nummer " + (i+1) + " ein!"));
}
JOptionPane.showMessageDialog(null, "Jetzt geht's Los!");
int max = map.size();
int removed = 0;
for(int i = 0; i < max; i++){
Random r = new Random();
int random = r.nextInt(max-1)+1;
JOptionPane.showMessageDialog(null, "Sie haben das Thema "+ map.get(random) + " gezogen!");
map.remove(random);
removed++;
}
}

The problem you're running into is that you can pick the same random number more than once, even if you've already removed the element with that key.
Instead of trying to pick non-duplicating random numbers, you would be better off to simply create a list of your keys, randomize their order, and then simply iterate over them.
Here's a simple example using strings that you should be able to adapt:
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Scratch {
public static void main(String[] args) throws Exception {
Map<Integer, String> map = new HashMap<>();
map.put(1, "foo");
map.put(2, "bar");
map.put(3, "baz");
List<Integer> keys = new ArrayList<>(map.keySet());
Collections.shuffle(keys);
for (Integer key : keys) {
String randomValue = map.get(key);
System.out.println(randomValue);
}
}
}

Related

Sorting algortithm with index in java

I have a set of values for srting algorithm. I have successfully sorted them out. But I also want to have the index for each element after sorting. For example like :
Array = [95, 53, 24, 10]
Output after sorting should be like :
10 at index 3, 24 at index 2, 53 at index 1 and 95 at index 0
I have used the following logic for sorting. But unable to get the indexes
for (int p = 0; p < ((list.size()) - 1); p++) {
int min = p;
count++;
for(int q=p+1; q<list.size();q++) {
if(doubleArray[q] < doubleArray[min]) {
min = q;
}
}
double smallNumber = doubleArray[p];
doubleArray[p] = doubleArray[min];
doubleArray[min] = smallNumber;
}
As this is probably homework, just some ideas:
before sorting, create a copy of your initial array
after sorting, iterate the original array, and then find the index of each value in the sorted array, and print that
the tricky part is dealing with values that show up repeatedly. but that is something that depends on your exact requirements.
Alternatively, you could look into introducing a helpful data structure, such as a Pair<Integer, Integer> class. The first entry represents the value, the second one an index. Then you can define your own "sorting" on that class.
As previously suggested, I would also recommend using an additional Item class which stores the item on which you want to sort and the initial index:
public class Item<T extends Comparable<T>> implements Comparable<Item<T>> {
public final T item;
public final int index;
public Item(T item, int index) {
if (item == null)
throw new NullPointerException("the given item is null!");
this.item = item;
this.index = index;
}
#Override
public int compareTo(Item<T> t) {
if (t == null)
return 1;
return item.compareTo(t.item);
}
}
When you need to sort the array of doubles, you first create an ArrayList containing the Items which store the doubles of the input array and the initial index. Since the Item class implements the Comparable interface, you can use Collections.sort for sorting (which will be faster than your bubblesort implementation):
public static void sort(Integer... array) {
List<Item<Integer>> copy = new ArrayList<Item<Integer>>(array.length);
// copy the input array
for (int i = 0; i < array.length; ++i)
copy.add(new Item<Integer>(array[i], i));
Collections.sort(copy);
for (Item<Integer> t : copy)
System.out.println(t.item + " at index " + t.index);
}
Try this:
Create a Pair class like
class Pair {
int val;
int index;
}
sort it by valuez
index will keep the initial index
I would suggest below approach:
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
public class trial
{
public static void main(String[] args)
{
List<Integer> aList = Arrays.asList(95, 53, 24, 10);
Map<Integer, Integer> aMap = new HashMap<>();
int index = 0;
for( Integer aInteger : aList )
{
aMap.put(aInteger, index);
index++;
}
SortedSet<Integer> keys = new TreeSet<>(aMap.keySet());
for( Integer key : keys )
{
Integer value = aMap.get(key);
System.out.println(key + " at index " + value);
}
}
}
Here you find the old index and shorted value
Map<Integer, Integer> map1 = numbers.stream().collect(Collectors.toMap(i -> i, i -> numbers.indexOf(i))). entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
(oldValue, newValue) -> oldValue, LinkedHashMap::new));
//output {10=3, 24=2, 53=1, 95=0}
I have just tried the following and it worked.
int[] index = {0,1,2,3}
for (int p=0;p<((list.size())-1);p++)
{
int min = p;
count++;
for(int q=p+1; q<list.size();q++)
{
if(doubleArray[q]< doubleArray[min])
{
min = q;
}
}
double smallNumber = doubleArray[p];
doubleArray[p] = doubleArray[min];
doubleArray[min] = smallNumber;
store = index[p];
index[p] = index[min];
index[min] = store;
}
}
and it worked.

Array are not selecting values randomly and split into two arrays

I have got an array list of animals, on click on 'select' button I
would like to randomly select these animals and pass animals into two
arrays (split) called 'teamA and teamB'. Here is my code, but I am getting the same array list always as per screenhot link ? Could someone please
help me to figure out the problem ?
import java.lang.Math;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
public class RandomExample {
private Random random = new Random();
public static void main(String[] args) {
// 'list' array list contains animals
List<String> list = new ArrayList<String>();
list.add("Tiger");
list.add("Crocodile");
list.add("Cat");
list.add("Dog");
list.add("Elephant");
list.add("Lion");
list.add("Deer");
list.add("Eagle");
RandomExample obj = new RandomExample();
for(int i = 0; i < 10; i++){
obj.getRandomList(list);
List<String> teamA = list.subList(0, 4);
List<String> teamB = list.subList(4, 8);
System.out.println(teamA);
System.out.println(teamB);
}
}
public String getRandomList(List<String> list) {
//0-4
int index = random.nextInt(list.size());
System.out.println("\nIndex :" + index );
return list.get(index);
}
}
As I asked I am not sure why you do not capture the returned string from getRandomList()… I am guessing you are thinking that the list gets returned? Another issue is that when you get a random number from the list you could get the same number. Therefore you will possibly get the same animal on both teams or even the same animal twice or more on the same team. When you put an animal on a team… you need to remove them from the list.
Below I create the two teams. Then setup two loops, one for each team. Using your getRandomList method to get a random animal then remove that animal from the list. After we have both lists, print the results. Hope this helps.
Edit: As per OP request to have a different number of animals for the teams.
Example: use 5 total animals for the teams.
Obviously it’s better to look at the amount of available data before you actually set the team sizes. Example: if you want teamB to have 5 and teamA to have 4, then there better be at least 9 animals in the list. So check the team sizes before you start the loops. If totalAnimalsForTeams is greater than the number of animals in the list or totalAnimalsForTeams is less than two , then we need to indicate this to the user and exit. This approach allows you to use only part of the list if needed. In the implementation below, if the totalAnimalsForTeams is an odd number the second loop will have the extra animal member.
public class Main
{
private static Random random = new Random();
public static void main(String[] args)
{
// 'list' array list contains animals
List<String> list = new ArrayList<String>();
list.add("Tiger");
list.add("Crocodile");
list.add("Cat");
list.add("Dog");
list.add("Elephant");
list.add("Lion");
list.add("Deer");
list.add("Eagle");
list.add("Monster");
list.add("Alien");
list.add("Vombie");
list.add("Politician");
list.add("Donkeye");
List<String> teamA = new ArrayList<String>();
List<String> teamB = new ArrayList<String>();
String newAnimal;
int totalAnimalsForTeams = 7; // <- probably get this value from the user?
if (totalAnimalsForTeams > list.size())
{
System.out.println("There are only " + list.size() + " animals in the list. Requested animals was: " + totalAnimalsForTeams);
return;
}
int firstHalf = totalAnimalsForTeams / 2;
if (firstHalf < 1)
{
System.out.println("Requested " + totalAnimalsForTeams + " animals for teams... not enough to make two teams!");
return;
}
for(int i = 0; i < firstHalf; i++)
{
newAnimal = getRandomList(list);
teamA.add(newAnimal);
list.remove(newAnimal);
}
int secondHalf = totalAnimalsForTeams - firstHalf;
for(int i = 0; i < secondHalf; i++)
{
newAnimal = getRandomList(list);
teamB.add(newAnimal);
list.remove(newAnimal);
}
System.out.println(teamA);
System.out.println(teamB);
}
public static String getRandomList(List<String> list) {
//0-4
if (list.size() > 1)
{
int index = random.nextInt(list.size());
//System.out.println("\nIndex :" + index );
return list.get(index);
}
else
{
return list.get(0);
}
}
}
try this .. it should work ..
import java.lang.Math;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Collections;
import java.util.Random;
public class RandomExample {
private Random random = new Random();
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("Tiger");
list.add("Crocodile");
list.add("Cat");
list.add("Dog");
list.add("Elephant");
list.add("Lion");
list.add("Deer");
list.add("Eagle");
RandomExample obj = new RandomExample();
List<String> teamA = list.subList(0,4);
List<String> teamB = list.subList(4,8);
for(int i = 0; i < 10; i++){
obj.getRandomList(list);
teamA = list.subList(0,4);
teamB = list.subList(4,8);
Collections.rotate(teamA, 1);
Collections.rotate(teamB, 1);
System.out.println(teamA);
System.out.println(teamB);
}
}
public String getRandomList(List<String> list) {
//0-4
int index = random.nextInt(list.size());
System.out.println("\nIndex :" + index );
return list.get(index);
}
}
Calling obj.getRandomList(list); returns a String but you donot do anything with it. I know this method is supposed to return a randomly picked item.
To correctly do what you are asking for, You would have to declare a new ArrayList say temp and then assign list to it.
To avoid Repetition of the same object, you need to remove the randomly generated item from the temp ArrayList created.
Then after you are done, remove the temp ArrayList created.
I have made the necessary changes to your main method as per the suggestions I made.
public static void main(String[] args) {
// 'list' array list contains animals
List<String> list = new ArrayList<String>();
list.add("Tiger");
list.add("Crocodile");
list.add("Cat");
list.add("Dog");
list.add("Elephant");
list.add("Lion");
list.add("Deer");
list.add("Eagle");
RandomExample obj = new RandomExample();
List<String> teamA = new ArrayList<String>();
List<String> teamB = new ArrayList<String>();
List<String> temp = list;
String animal;
for(int i = 0; i < 10; i++){
if(temp.isEmpty() == false){
animal = obj.getRandomList(temp);
if(i <= 3){
teamA.add(animal);
}else{
teamB.add(animal);
}
temp.remove(animal);
//System.out.println("temp is "+temp);
}
}
temp.clear();
System.out.println(teamA);
System.out.println(teamB);
}

Comparator to get the maximum value in Linked List with exclude the first element of the Linked List from the comparison

I am trying to extract the maximum value from the LinkedList,but with one condition that I want the first element of the LinkedList being out of the comparison and without relying on the values stored inside the first element.
Can I use the index of the LinkedList or whatever to exclude the first element through the comparison.
This is what I have done but I do not know how implement this condition:
import java.util.*;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class HelloWorld{
public static void main(String args[]) {
// create a linked list
LinkedList<HashMap<Integer, Integer>> PathList = new LinkedList<HashMap<Integer, Integer>>();
Integer n = new Integer(0);
// add elements to the linked list
for(int i=1; i<4; i++){
HashMap<Integer, Integer> PMap = new HashMap<Integer, Integer>();
PMap.put(1,0);
PMap.put(2,i);
PMap.put(3,2*i);
PathList.add(n,PMap);
n++;
}
Iterator x = PathList.listIterator(0);
// print list with the iterator
while (x.hasNext()) {
HashMap<Integer, Integer> PMap = new HashMap<Integer, Integer>();
PMap = (HashMap<Integer, Integer>)x.next();
System.out.println(PMap.get(3));
}
Comparator<HashMap> cmp = new Comparator<HashMap>() {
#Override
public int compare(HashMap hm1, HashMap hm2) {
return new Integer((Integer)hm1.get(3)).compareTo(new Integer((Integer)hm2.get(3)));
}
};
System.out.println("Max value in this element " + Collections.max(PathList,cmp));
}
}
You can create a sublist from the original list (it is just a view, it doesn't copy all the elements).
So you can change:
System.out.println("Max value in this element " + Collections.max(PathList,cmp));
To:
LinkedList<HashMap<Integer, Integer>> pathListWithoutFirst = PathList.subList(1, PathList.size());
System.out.println("Max value in this element " + Collections.max(pathListWithoutFirst, cmp));
Aside from Collections.max, you can do the implementation your own like this-
public int getMaxValue(LinkedList<Integer> list){
int max = Integer.MIN_VALUE;
/* We used i = 1 below to exclude first element as your needs.
But to include all elements, use i = 0 */
for(int i = 1; i < list.size(); i++){
if(list.get(i) > max){
max = list.get(i);
}
}
return max;
}
Note that calling the above method with zero or one item in the list will return the Integer.MIN_VALUE which is -2147483648.

Making distinct selections from the given list

I am trying to make a team of unique members from the given set I have. This is what I have so far.
import java.util.*;
import java.lang.*;
class Main
{
public static void main (String[] args) throws java.lang.Exception
{
/* Putting all team-mates in HashMap */
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
map.put("d", 4);
/* Printing out the random name and the Unique number with it*/
List<Integer> valuesList = new ArrayList<Integer>(map.values());
List<String> keyList = new ArrayList<String>(map.keySet());
System.out.println("The Team members are :");
for (int i = 0; i < 3; i++)
{
int randomIndex = new Random().nextInt(valuesList.size());
Integer randomValue = valuesList.get(randomIndex);
String randomKey = keyList.get(randomIndex);
System.out.println(randomValue+" "+randomKey);
}
}
}
When I run this, I get duplication in my list, do I use Collections.shuffle(valuesList)?
Thank You.
You can get the same number randomly twice, so Collections.shuffle(...) should do.
If a,b,c,d is all you are after, this is how I would do it:
import java.util.*;
import java.lang.*;
class Main
{
public static void main (String[] args) throws java.lang.Exception
{
/* Putting all team-mates in a List*/
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
/* Printing out the random name */
System.out.println("The Team members are :");
for(int i = 0; i < 3; i++)
{
int randomIndex = new Random().nextInt(list.size());
//Integer randomValue = valuesList.get(randomIndex);
String randomValue = list.remove(randomIndex);
//String randomKey = keyList.get(randomIndex);
System.out.println(randomValue);
}
}
}
removing chosen elements from the list once chosen will make sure they don't reappear.
Fewer lines too.

Put substring as key and the following substring as value into a TreeMap

Example:
String wholeString =
"Typical models for star formation assume that every type of galaxy produces stars"
I'd like to store the splitted string and its following (+1) String in a treemap:
with windowSize = 4 (predefined):
Typi,ypic -> put into TreeMap
ypic,pica -> put into TreeMap
for windowSize = 2 it would look like this:
Ty,yp -> TreeMap
and so on.
My code so far:
Map<String, String> generateMap = new TreeMap<String, String>();
for (int i = 0; i < wholeString.length(); i++) {
generateMap
.put((wholeString.substring((i),
Math.min((i + windowSize), wholeString.length()))),
(wholeString.substring(
(i + 1),
(Math.min((i + windowSize),
wholeString.length())))));
}
If I sysprint it, I gets this:
{ Augen=Augen, Außen=Außen, Innen=Innen, Jauch=Jauch,and so on
My take:
final String wholeString =
"Typical models for star formation assume that every type of galaxy produces stars";
final int windowSize = 4;
final Map<String, String> generateMap = new LinkedHashMap<String, String>();
final int limit = wholeString.length() - windowSize;
for (int i = 0; i < limit;) generateMap.put(
wholeString.substring(i, i + windowSize),
wholeString.substring(++i, i + windowSize));
for (Map.Entry<String, String> e : generateMap.entrySet())
System.out.println(e.getKey() + " -> " + e.getValue());
Here you go (I changed the TreeMap by a LinkedHashMap for debug purposes, you can put back the TreeMap if your prefer):
import java.util.LinkedHashMap;
import java.util.Map;
public class Test {
/**
* #param args
*/
public static void main(String[] args) {
Map<String, String> generateMap = new LinkedHashMap<String, String>();
String wholeString = "Typical models for star formation assume that every type of galaxy produces stars";
int windowSize = 4;
for (int i = 0; i < wholeString.length(); i++) {
int start = i;
int end = Math.min(i + windowSize, wholeString.length());
int start1 = Math.min(i + 1, wholeString.length() - 1);
int end1 = Math.min(i + 1 + windowSize, wholeString.length());
generateMap.put(wholeString.substring(start, end), wholeString.substring(start1, end1));
}
System.err.println(generateMap);
}
}
If you like recursion, you may try this:
import java.util.LinkedHashMap;
import java.util.Map;
public class Subs {
/**
* #param args
*/
public static void func(Map<String,String> map, String input, int windowSize) {
if (input.length() <= windowSize) {
map.put(input, input);
return;
} else {
map.put(input.substring(0, windowSize), input.substring(1, windowSize + 1));
func(map, input.substring(1), windowSize);
}
}
public static void main(String[] args) {
String wholeString = "Typical models for star formation assume that every type of galaxy produces stars";
Map<String,String> ourMap = new LinkedHashMap<String, String>();
int windowSize = 4;
func(ourMap, wholeString, windowSize);
System.out.print(ourMap);
}
}
Please note that I'm using 'LinkedHashMap', so output will be in order you put values into it. If you need to put into a TreeMap, simply replace LinkedHashMap with TreeMap and add import statement. But result will be sorted in natural order, not the order you put your values in.

Categories