0

I am trying to compare the keys of my data in a hashmap to check if the data exists. However, even when the key does exist in the array, containsKey will still return false. I am using this:

package timeTraveler.core;

import java.util.Arrays;

public class StringArrayHolder
{
    private final String[] data;
    //I do not want any client could change the array reference
    //this also explains why this field doesn't have a setter
    public StringArrayHolder(String[] data) 
    {
        this.data = data;
    }
    public String[] getData() 
    {
        return this.data;
    }
    @Override
    public int hashCode()
    {
        return Arrays.hashCode(data);
    }
    @Override
    public boolean equals(Object o)
    {
        if (o == null) 
        {
            System.out.println("NULL");
            return false;
        }
        if (o == this)
        {
            System.out.println("THIS");
            return true;
        }

        if (o instanceof StringArrayHolder) 
        {
            StringArrayHolder other = (StringArrayHolder)o;
            return Arrays.equals(this.data, other.data);
        }
        return false;
    }
    //just to print in console for testing purposes
    @Override
    public String toString() 
    {
        return Arrays.deepToString(data);
    }
}

And my compare:

package timeTraveler.mechanics;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import timeTraveler.core.StringArrayHolder;

public class PathingData 
{
    /**
     * Entity data array
     */
    public Map<StringArrayHolder, List<int[]>> allEntityData;

    public PathingData()
    {
        allEntityData = new HashMap<StringArrayHolder, List<int[]>>();
    }
    /**
     * Adds an entity identifier (NBT)and MobType to the entity data ArrayList.  If the entity already exists inside of the ArrayList, then it skips it.
     * @param uuid
     */
    public void addEntity(StringArrayHolder entityData)
    {       
        System.out.println(entityData);
        if(!allEntityData.containsKey(entityData))
        {
            System.out.println("Adding entity!");
            allEntityData.put(entityData, new ArrayList<int[]>());
        }
        else
        {
            System.out.println("ENTITY ALREADY EXISTS IN ARRAY");
        }
    }
    /**
     * Adds data (X, Y, and Z) to the corresponding identifier (NBT) for the entity.  If the entity's identifier does not exist, then it prints out a line that says the identifier cannot be found.
     * @param uuid
     * @param data
     */
    public void addData(StringArrayHolder entityData, String data)
    {
        System.out.println(entityData);
        if(allEntityData.containsKey(entityData))
        {
            System.out.println("Adding data to entity!");
            int[] rawData = new int[3];
            String[] pureData = data.split(",");

            rawData[0] = Integer.parseInt(pureData[0]);
            rawData[1] = Integer.parseInt(pureData[1]);
            rawData[2] = Integer.parseInt(pureData[2]);

            List<int[]> entityLocData = allEntityData.get(entityData);
            entityLocData.add(rawData);
            allEntityData.put(entityData, entityLocData);
        }
        else
        {
            System.out.println("ENTITY DOES NOT EXIST IN ARRAY! :(");
        }
    }
    /**
     * Gets the data for a specific UUID (Unique ID) for an entity.
     * @param uuid
     * @return
     */
    public List<int[]> getDataForIdentifier(StringArrayHolder entityData)
    {
        List<int[]> entityLoc = allEntityData.get(entityData);
        return entityLoc;
    }
    /**
     * Clears all entities and their corresponding data from the map.
     */
    public void clearAllEntitiesAndData()
    {
        allEntityData.clear();
    }

    /**
     * Checks if entity exists inside of array
     * @param entityData
     * @return
     */
    public boolean doesEntityExist(StringArrayHolder entityData)
    {
        System.out.println(entityData);
        if(allEntityData.containsKey(entityData) || allEntityData.containsValue(entityData))
        {
            System.out.println("ENTITYDOESEXISTINARRAY :)");
            return true;
        }
        System.out.println("ENTITY DOES NOT EXIXT IN ARRAY!  :(");
        return false;
    }

    @Override
    public String toString() 
    {
        return allEntityData.toString();
    }

}

Area where doesEntityExist is called:

package timeTraveler.entities;

import java.util.Random;
import java.util.UUID;

import timeTraveler.core.StringArrayHolder;
import timeTraveler.core.TimeTraveler;
import timeTraveler.gui.GuiTimeTravel;

import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.passive.EntityWolf;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.event.ForgeSubscribe;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;

public class EntityHandler 
{
    boolean inPast;

    @ForgeSubscribe
    public void onEntityJoin(EntityJoinWorldEvent event)
    {

        inPast = GuiTimeTravel.isInPast;

        if(event.entity instanceof EntityLiving && !(event.entity instanceof EntityPlayer))
        {
            NBTTagCompound entityData = event.entity.getEntityData();
            Random rand = new Random();

            if(entityData.getInteger("identifier") == 0)
            {
                entityData.setInteger("identifier", rand.nextInt());
            }

            String[] data = new String[2];

            String identifier = Integer.toString(event.entity.getEntityData().getInteger("identifier"));
            String entityName = event.entity.getEntityName();

            data[0] = identifier;
            data[1] = entityName;

            StringArrayHolder d = new StringArrayHolder(data);

            if(inPast)
            {
                System.out.println(data[0]);
                System.out.println(data[1]);
                System.out.println(d);
                if(!TimeTraveler.vars.pathData.doesEntityExist(d))
                {
                    System.out.println("REMOVING ENTITY");

                    //event.entity.setDead();
                }
                else
                {
                    System.out.println(":)");
                }
            }
        }
    }

}

Specifically, doesEntityExist is always returning false. the data does exist in the array, yet for some reason it still returns false. Any ideas?

Charsmud
  • 183
  • 1
  • 4
  • 19
  • Where are you calling `doesEntityExist` from and what are you passing to it, when you observe this behaviour? – Dawood ibn Kareem Nov 05 '13 at 04:08
  • Please paste your code, where calling doesEntityExist always return false. I ran an example, and it will return true. Code is as follows: StringArrayHolder holder = new StringArrayHolder(new String[] { "Hello", "Java" }); PathingData data = new PathingData(); data.addEntity(holder); System.out.println(data.doesEntityExist(holder)); – Mengjun Nov 05 '13 at 04:45
  • 1
    Your array is still mutable (i.e. can be changed by the client). If this is happening, then that could explain why doesEntityExist is returning false. At minimum, you should make a copy of the inbound array in the constructor instead of holding a reference. Also, how sure are you that the members of the array are immutable? If their hashcodes can change, then the hashcode of the array holder will also change. – Kevin Day Nov 05 '13 at 05:19
  • I've added the code that calls the doesEntityExist. – Charsmud Nov 05 '13 at 05:23
  • Are you aware of and okay with the fact that doing `someStringArrayHolder.getData()[0] = "blah";` will change the internal array? – Boann Nov 05 '13 at 05:29
  • I'm unsure what you mean... I'm not using that anywhere that I know of. If it can fix my problem, I would be fine with it. – Charsmud Nov 05 '13 at 05:34
  • @Charsmud It may have nothing to do with your current problem. I just mean that it looks like StringArrayHolder was intended to be immutable, but it isn't, because one can obtain the array object by calling getData(), or hold on to the array object after calling the constructor. – Boann Nov 05 '13 at 05:43
  • Is there a way to fix this? I have had this problem for a while and just haven't been able to figure out the problem and how to fix it. – Charsmud Nov 05 '13 at 05:45
  • @Charsmud Which problem? If you mean the mutable array, see http://stackoverflow.com/questions/3700971/immutable-array-in-java. If you mean, why does `doesEntityExist` always return false, I have no idea but I suppose the entity doesn't exist (in `TimeTraveler.vars.pathData`). Post an [SSCCE](http://sscce.org/) if you can. – Boann Nov 05 '13 at 05:54
  • It states: "Not with primitive arrays. You'll need to use a List or some other data structure: List items = Collections.unmodifiableList(Arrays.asList(0,1,2,3));" Is a HashMap considered a primitive array? – Charsmud Nov 05 '13 at 05:59
  • @Charsmud No no, it means whether the array elements are primitives. E.g., `int` is a primitive, `String` isn't. Again, this might not have anything to do with your HashMap problem. – Boann Nov 05 '13 at 06:06
  • so change my int[] array to Integer[] array? – Charsmud Nov 05 '13 at 06:16
  • @Charsmud Huh? You don't have an int[] you have a String[]. – Boann Nov 05 '13 at 06:22
  • I'm talking about this line: allEntityData = new HashMap>(); Although I'm still confused on how I would fix this. – Charsmud Nov 05 '13 at 23:16
  • Oh. Is this a third problem? I suppose you could do it as a `HashMap>>` but it doesn't make much difference. Assuming your inner ints represent a position, a `HashMap>` would be nicer, where your Vector3 is something like `class Vector3 { public final int x,y,z; public Vector3(int x, int y, int z) { this.x = x; this.y = y; this.z = z; } }`. – Boann Nov 06 '13 at 00:58
  • Would this fix the data not being detected as in the HashMap? It was stated by Kevin that I should make my array immuteable: how would I do this? – Charsmud Nov 06 '13 at 01:39
  • No that's surely unrelated because it's the value rather than the key. He and I were referring to the String[] in StringArrayHolder being mutable. Fixing that might fix doesEntityExist, but I suspect the data is simply not in the map. However, you can make StringArrayHolder immutable if wanted by cloning the array in the constructor: `this.data = data.clone();` and by either removing `getData()` or having it return a clone: `return this.data.clone();`. Or, simply using a `Collections.unmodifiableList(Arrays.asList("a", "b", "c"))` would make the StringArrayHolder class unnecessary. – Boann Nov 06 '13 at 06:14
  • I have tried making StringArrayHolder immutable, but this did not fix the problem; I cannot seem to figure out why the data is not being recognized as in the HashMap. – Charsmud Nov 19 '13 at 05:27
  • I read your code again in case I missed something. My main suggestion is the same as it was two weeks ago: Most likely the entity is simply not in the map. Whatever the problem is, reducing the code to an [SSCCE](http://sscce.org/) will surely flush it out. – Boann Nov 21 '13 at 13:10
  • Is there any other way to do what I am trying to do? I'm really having problems with this. If it's not clear what I'm doing, I am saving data to a HashMap data structure and comparing that data to an input: If the input matches something in the hashmap, it returns true. It would need to be able to have any number of inputs (ie, it saves a String, int, double, and a float) and be able to compare input values to these. – Charsmud Nov 23 '13 at 01:49
  • When you say "data" and "input", I don't know which one you intend as the map's key and which one you intend as the map's value. But using a map is as simple as `map.put(key, value)` to store something and `map.get(key)` to retrieve the value. For a HashMap, make sure your key type implements `equals` & `hashCode` correctly (which it does), or for a TreeMap (less common), make sure it implements `compareTo`. Immutable key & value types can simplify things but it's not strictly required. If `containsKey` still returns false after doing the above, then the equal key simply isn't in that map. – Boann Nov 23 '13 at 02:19
  • You can test the sanity of `Map.containsKey` by testing it for every element that it does contain. For example: `for (StringArrayHolder sah : allEntityData.keySet()) System.out.println(allEntityData.containsKey(sah));` That should print `true` for every element. – Boann Nov 23 '13 at 02:26
  • The test did print true for every element. When I say "data" and "input", data is the variables stored and input is what is comparing itself to the data. I was thinking of just combining all the data into one wrapper-class, but I don't believe that will fix it. – Charsmud Nov 23 '13 at 19:11

0 Answers0