13

I am fairly new to Java and am having trouble understanding the differences between different collections. I have a list of 19 resources. Each resource is assigned a hex color. I want to get a random resource with its color and use that resource with my code. Once I am finished with the current resource, I want to remove it from the list so that only a certain number of resources are used.

Should I use a dictionary, map, or hashtable? Or any others that I am missing.

yakobom
  • 2,681
  • 1
  • 25
  • 33
ShoeLace1291
  • 4,551
  • 12
  • 45
  • 81
  • `List` might work for your specific use case. Do you imagine you will ever need to lookup a resource based on something like the hex color? – Tim Biegeleisen Jan 18 '17 at 07:57
  • 1
    I don’t understand your exact requirements, but if something like a dictionary or map, then `HashMap` would be the standard choice. – Ole V.V. Jan 18 '17 at 07:58
  • 7
    Need more information. Do you need them sorted in any way? Can a resource be added more than once? Does the resource got an identifier of some sort which is available to you and you search by it for a specific resource, or do you just go over all the resources at once and use them? – CodeMonkey Jan 18 '17 at 07:59
  • I would either need to shuffle the elements or be able to get a random element one at a time. I don't think I would have the need to get a resource by it's color. – ShoeLace1291 Jan 18 '17 at 08:02
  • So it sounds like a map is ruled out. Can a resource be added more than once? – CodeMonkey Jan 18 '17 at 08:04
  • In my opinon, even ArrayList works fine if you are looking for fast access. For quick adding and removal, you can consider LinkedList. – user3437460 Jan 18 '17 at 08:05
  • 5
    since you have only 19 items, use whatever you want. you'll never notice a change – AdamSkywalker Jan 18 '17 at 08:06
  • 5
    `ArrayList` is fine. `Collections.shuffle()` will make sure you get your ressorces out in random order. – Ole V.V. Jan 18 '17 at 08:07
  • ArrayList wouldn't work because I need to assign the color(value) to the resource(key) – ShoeLace1291 Jan 18 '17 at 08:09
  • @ShoeLace1291 Do you need 1 to 1 mapping for color and resource? More importantly, must the color value be unique in your collection? – user3437460 Jan 18 '17 at 08:13
  • 1
    well, i'm starting to wonder what are the **19 resources** actually are.. as one answer pointed out, it may a class that contains the color.. but, you did mention a map - key-value relationship.. – Bagus Tesa Jan 18 '17 at 08:15
  • 2
    @ShoeLace1291 you wrote at first " I don't think I would have the need to get a resource by it's color" and then you write "I need to assign the color(value) to the resource(key)"... So what is it? – CodeMonkey Jan 18 '17 at 08:19

4 Answers4

11

What you could do, is store your resources into a List, then randomly permutes it thanks to Collections.shuffle(List<?> list) or shuffle(List<?> list, Random rnd), and finally call iterator() on the resulting list to get an instance of Iterator that you could store into a member field to be able to iterate over your list (thanks to hasNext()/next()) and remove your resource once done with remove().

Here is a pseudo code using String as resource just to show the idea:

// Create a read/write list (Arrays.asList returns a read-only list)
List<String> resources = new ArrayList<>(Arrays.asList("1", "2", "3"));
System.out.printf("Initial state = %s%n", resources);
Collections.shuffle(resources);
System.out.printf("Permuted List = %s%n", resources);
Iterator<String> iterator = resources.iterator();
if (iterator.hasNext()) {
    String resource = iterator.next();
    // do something
    iterator.remove();
    System.out.printf("After remove = %s%n", resources);
}

Output:

Initial state = [1, 2, 3]
Permuted List = [3, 1, 2]
After remove = [1, 2]

NB: This approach makes sense in your case as you have a small list, please note that if you have a big list and you intend to retrieve only a small part of it, you should consider using a Random to get randomly the index of the next element (using nextInt(int bound) with list.size() as parameter) to get (using get(int index)) and remove (using remove(int index)) instead of using Collections.shuffle(List<?> list) as it would cause an overhead.


ArrayList wouldn't work because I need to assign the color(value) to the resource(key)

Yes it can work if you use a List of a wrapper class that will contain both, your color and your resource (for example AbstractMap.SimpleImmutableEntry or simply a custom class). It is good enough as you don't seem to need to retrieve the color by resource. If you do, you could simply have a Map with resource as key and color as value and use new ArrayList<>(map.keySet()) to initialize your list of resources, then you will be able to apply what is proposed previously in this answer.

Nicolas Filotto
  • 43,537
  • 11
  • 94
  • 122
  • 1
    Note that if only a small fraction of elements from the initial list is picked randomly, shuffling the whole list causes overhead for large lists. – SpaceTrucker Jan 18 '17 at 10:47
  • @SpaceTrucker I agree but here the list is composed of only `19` elements so I don't believe that the overhead would be so big in this case especially if it is done only once, the overhead would then be insignificant. – Nicolas Filotto Jan 18 '17 at 11:36
  • Note that the `new ArrayList` is necessary since the one returned from `Arrays.asList` would throw an `UnsupportedOperationException` when you try to remove an element. – JollyJoker Jan 18 '17 at 12:37
  • @JollyJoker yes that's right, `Arrays.asList` returns a read only list – Nicolas Filotto Jan 18 '17 at 12:39
  • @NicolasFilotto You are right, That's why I also upvoted your answer. But since this question already received some upvotes a larger audience may reuse your ideas and I think its good if they are aware of the possible overhead. – SpaceTrucker Jan 18 '17 at 12:43
  • @NicolasFilotto Meant more as an FYI for others reading your answer, obviously you knew. – JollyJoker Jan 18 '17 at 12:48
3

If you want to lookup (get) resource based on its hex use following

// Initialize
Map<String, Resource> resourceMap = new HashMap<>();
resourceMap.put("hex1", hex1Resource);
resourceMap.put("hex2", hex3Resource);
resourceMap.put("hex3", hex3Resource);

// Get specific
Resource hex2Resource = resourceMap.get("hex2");
resourceMap.remove("hex2");

If you want to lookup resource randomly, there are 2 options

  • Use List (this allows duplicates)
  • Use Set (stores only unique values)

Using Lists

// Initialize
List<Resource> list = new ArrayList<>();
list.add(resource1);
list.add(resource2);
list.add(resource3);

// Get random
Random rand = new Random();
Resource randomResource = list.get(rand.nextInt(list.size()));

// Delete the element from list
list.remove(randomResource);

Using Sets

// Initialize
Set<Resource> set = new HashSet<>();
set.add(resource1);
set.add(resource2);
set.add(resource3);

// Convert to List, since Set does not have get(int) method. 
List<Resource> list = new ArrayList<>(set);

// Get random
Random rand = new Random();
Resource randomResource = list.get(rand.nextInt(list.size()));

// Delete the element from list
list.remove(randomResource);

Note: For both cases above, Resource class will need to implement methods equals and hashcode so that list/set can compare elements and work correctly. See Java equals and hashcode

Update: Sets do not have get(int) method. Updated the code to fix this.

DeepakV
  • 2,420
  • 1
  • 16
  • 20
0

The following should work. The steps are:

  1. Create a list of Resource
  2. Generate a random number and get the item
  3. Do what you want to do with your random item
  4. Remove it from list

Example Code:

 //1
List<Resource> resources= getList();

//2
Random generator = new Random();
Resource randomResource = resources.get(generator.nextInt(resources.size() -1));

//3
//do your stuff

//4
resources.remove(randomResource);

Resource can be a class which wraps your data

class Resource{
    String color;
    String otherProperties;
    //..


    @Override
    public boolean equals(Object obj) {
        //generate from IDE or write one
    }

    @Override
    public int hashCode() {
        //generate from IDE or write one
    }
}
gtiwari333
  • 24,554
  • 15
  • 75
  • 102
0

Blockquote

if u need random order better you can go for List object.

List<String> resourceMap = new CopyOnWriteArrayList<>();
          resourceMap.add("hex1");
          resourceMap.add("hex2");
          resourceMap.add("hex3");
          resourceMap.add("hex4");
          Collections.shuffle(resourceMap);
          resourceMap.forEach(resource->{
              resourceMap.remove(resource);
          });
Shivakoti
  • 1
  • 3