3

I have a list of models (DocumentSnapshot from Firestore) that have an id (String). I need to create a notification for each of them, they could be many (messages from a chat) and I need to use an int id to assign to the notification. I need to use their String id since I could receive an updated version of that model, so I want to update the notification front that precise model. What could be a solution?

4face
  • 590
  • 1
  • 8
  • 18

4 Answers4

5

There is inpossible to produce unique int id from infinite set of Strings. But you can use a good hash function for your purpose - in most cases it would be good enough. Please consider using something better than common #hashCode implementation. I would suggest you to look into https://github.com/google/guava/wiki/HashingExplained

and use at least murmur3 algorithm. The code snippet looks like:

import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;

public class Main {

    public static void main(String[] args) {
        System.out.println(
                Hashing.murmur3_32()
                .newHasher()
                .putString("Some Sting", Charsets.UTF_8)
                        .hash().asInt());
    }
}
rhkcoo
  • 91
  • 4
  • Yes I know, but I want reduce at the minium the possibility of duplicates. It was easier with Realtime Database, where id was generated basing on the time, but now, with Firestore, they are completely random. – 4face Dec 29 '17 at 17:29
4

Do it like this

int uniqueNumber = myString.hashCode()

Greggz
  • 1,873
  • 1
  • 12
  • 31
  • The `hashCode` generated by `String.hashCode()` is not that good that you won't hit collisions easily. Better to use a good cryptographic hash code. – Mark Rotteveel Dec 29 '17 at 19:20
  • 1
    Example: `"DNS185".hashCode() == "E04185".hashCode()` yields true. – neu242 Dec 06 '19 at 11:14
3

Thanks to I found best solution as:

public static int hashCode(String string) {
    return Hashing.murmur3_32()
            .newHasher()
            .putString(string, Charsets.UTF_8)
            .asInt());
} 

Or, with String.hashCode() Thanks to Greggz & navy1978:

public static int hashCode(String string) {
    return string != null ? string.hashCode() * PRIME : 0;  // PRIME = 31 or another prime number.
}

or this for a @NonNull value

public static int hashCode(@NonNull String string) {
    return string.hashCode() * PRIME;  // PRIME = 31 or another prime number.
}
4face
  • 590
  • 1
  • 8
  • 18
1

You can try, as Greggz has already suggested, to use the hashCode, Eclipse, for instance, suggests this implementation (where the variable "b" is your String):

public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((b == null) ? 0 : b.hashCode());
    return result;
}

Of course you can change/adapt it to your needs...

navy1978
  • 1,411
  • 1
  • 15
  • 35
  • Thanks, I didn't know about HashCode, but why add 1 and multiply for 31? – 4face Dec 29 '17 at 13:46
  • 1
    short answer: it's about convention, long answer: We add 1 because we want a non-zero value, and 31 is an arbitrary prime number, you can use another one if you like. If you want to have more info about that, you can have a look here: https://stackoverflow.com/questions/3613102/why-use-a-prime-number-in-hashcode – navy1978 Dec 29 '17 at 13:53
  • Would not be better to do: int result = string.hashCode(); result = result != 0 ? result : 1; return result * 31; ? – 4face Dec 29 '17 at 14:01
  • You can play with it, but be careful, string.hasCode() can throw an Exception if string is null... that's why in my answer you have (b==null)? 0: b.hashCode(), remember that in my example b is your string... – navy1978 Dec 29 '17 at 14:04
  • Yes, of course I would also handle that, but also DocumentSnapshot.getId() returns a NonNull value – 4face Dec 29 '17 at 14:07
  • 1
    Ah Ok, it depends on how the original String is generated, in your implementation you have a not-null one, but I was speaking more generally... – navy1978 Dec 29 '17 at 14:10