0

I have strings of digits ('numbers') that correspond to strings, not all matches are unique, but the numbers are. Nothing changes, it's all constant. Something like this:

10023 - "Hugo" - "Boss"
023 - "Big" - "Boss"
1230 - "Hugo" - "A or B"
// ...and about twenty more like that

what i want, is to be able to receive a string of digits, and then get the two strings for that.

The enum way isn't neat, because i cannot call the enum a number (needs a leading non-digit), otherwise i could go with the whole song-and-dance of defining an enum and then getting the values by looking for the right one with Enum.valueOf(), and the method way is not neat because it is ugly and unreadable during definition.

public class detailsForNumber {
   public String first;
   public String second;
   public detailsForNumber(String number) {
   if (number == "10023") {
      first = "Hugo";
      second = "Boss";
   } else if (number == "023")
//.....and so on 

//Then i could later and somewhere else go:

Somewhere.detailsForNumber dFN = Somewhere.detailsForNumber("023");
System.out.println(dFN.first); // Prints 'Big'

   

is there a readable way to define this relationship somewhere and then a reasonable way to get the strings out of there?

Ideally it would be a non-headache to later add a third string, or have a non-digit character in the 'number', but there will be no changes at runtime.

bukwyrm
  • 186
  • 6
  • 2
    Relevant: [How do I compare Strings in Java?](https://stackoverflow.com/questions/513832/how-do-i-compare-strings-in-java) – maloomeister Nov 09 '21 at 07:09
  • Stop calling them nubers, it is confusing as you have to constantly remind that "they're not numbers because of the leading zeros" (they're strings that consist of digits). You need a custom data type (class) that represents the actual use case you have for "holding a key and two values." The implementation most likely should be split into two classes: one class that contains the values and one class that acts as a repository (i.e. maps the keys to the value containers). – Torben Nov 09 '21 at 07:13
  • Create your own `Details` class containing the three `String`s each and in your `DetailsForNumber` class, hold a `List
    `, where you can check and retrieve the correct details.
    – maloomeister Nov 09 '21 at 07:13
  • Although @bukwyrm you don't want enums, you would like your code to be clean. I think it would be neater as an enum with two string values. the method for finding the strings would be shorter also. it would be something like values.stream().filter().findAny() – Nora Na Nov 09 '21 at 07:16
  • @NoraNa The enum.values() is a horribly ineficient method. It should not be used for repeated lookups. Then the stream processing also creates unnecessary objects (except that you can't just stream over an array, you have to use Arrays.stream(...)). The correct way do this is to use a Map with statically initialized data. – Torben Nov 09 '21 at 07:20

4 Answers4

1

I would go with creating a class that has three attributes.

  1. key of type String (the leading zero unique numbers that you have)
  2. str1 the String value 1
  3. str2 the String value 2

And then create another class that keeps all your Data. You can then filter using streams.

For example:

public class Data
{
    private String key;
    private String str1;
    private String str2;

    // Getters, setters, equals...
    
}

public class DataList
{
    private List<Data> list = new ArrayList<>();
    
    public boolean addDataToList(Data newData)
    {
        boolean isDuplicate = list.stream().anyMatch(data -> data.getKey().equals(newData.getKey()));
        
        if(isDuplicate)
        {
            return false;
        }
        
        list.add(newData);
        return true;
    }

    public Data getThroughKey(String key)
    {
        Optional<Data> opt = list.stream().filter(data -> data.getKey().equals(key)).findFirst();

        // Or handle it 
        return opt.orElse(null);
    }
    
    // Getters, setters and whatever else you need
}

You could also use a Set which takes care of duplicates without you explicitly checking. But you must override the equals() and hashCode() functions in your Data class. I do not know which one of them is more efficient. That's a story for another question.

Renis1235
  • 4,116
  • 3
  • 15
  • 27
  • Isn't this overkill for something that is constant? – bukwyrm Nov 09 '21 at 07:33
  • To be honest, I would actually use a DB for something even so small. Why reinvent the wheel? You could add some constraints on your Table, and there would be no need to initialize the data every time the app is started. So long story short, IMO it is not overkill. – Renis1235 Nov 09 '21 at 07:42
1

If it's all constant and static data then you may use a simple switch:

class Name {
    private String first;
    private String second;

    private Name(final String first, final String second) {
        this.first = first;
        this.second = second;
    }

    public String getFirst() { return first; }
    public String getSecond() { return second; }

    public static Name forNumber(final String number) {
        switch (number) {
            case "10023": return new Name("Hugo", "Boss");
            case "023":   return new Name("Big", "Boss");
            case "1230":  return new Name("Hugo", "A or B");

            default: return null;
        }
    }

};

class Main {
    public static void main(String args[]) {
        final String number = "023";
        final Name n = Name.forNumber(number);
        if (n == null) {
            System.out.println("Not found");
            return;
        }
        System.out.printf("%s -> {%s, %s}\n", number, n.getFirst(), n.getSecond());
    }
}

See online

If the data is loaded at runtime, you may use HashMap.

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
1

Try this.

public enum DetailsForNumber {
    E10023("10023", "Hugo", "Boss"),
    E023("023", "Big", "Boss"),
    E1230("1230", "Hugo", "A or B");
    
    public final String number, first, second;
    private static final Map<String, DetailsForNumber> map = new HashMap<>();
    static {
        for (DetailsForNumber e : values())
            map.put(e.number, e);
    }
    
    private DetailsForNumber(String number, String first, String second) {
        this.number = number;
        this.first = first;
        this.second = second;
    }
    
    public static DetailsForNumber get(String number) {
        return map.computeIfAbsent(number,
            k -> { throw new IllegalArgumentException("number"); });
    }
}

public static void main(String[] args) {
    DetailsForNumber dFN = DetailsForNumber.get("023");
    System.out.println(dFN.first);
}

output:

Big
1

using enum like below:

public enum NumberDetails {
    // it's a demo, you can define the name more meaningful.
    NUMBER_1("10023", "Hugo", "Boss"),
    NUMBER_2("023", "Big", "Boss"),
    NUMBER_3("1230", "Hugo", "A or B");

    private String number;
    private String first;
    private String second;

    static Map<String, NumberDetails> CACHE_MAP = Arrays.stream(values())
                    .collect(Collectors.toMap(NumberDetails::getNumber, it -> it, (a, b) -> a));

    public static NumberDetails from(String number) {
        return CACHE_MAP.get(number);
    }

    NumberDetails(String number, String first, String second) {
        this.number = number;
        this.first = first;
        this.second = second;
    }

    public String getNumber() {
        return number;
    }

    public String getFirst() {
        return first;
    }

    public String getSecond() {
        return second;
    }
}

and a simple usage:

public class NumberDetailsTest {
    public static void main(String[] args) {
        System.out.println(NumberDetails.from("023").getFirst());
    }
}
Ethan
  • 126
  • 3