2

Is it possible to have an implementation for hash, where key is String and value is function. For the background, I have a program where there is lots of string comparison, i.e.

if(s.equalsIgnoreCase("london")  
   functionA();  
else if(s.equalsIgnoreCase("moscow")  
   functionB();  
else if(s.equalsIgnoreCase("delhi")  
   functionC();  
  ...  

and so on.

But this kind of implementation is very costly (theta(n)), since String comparison is done for all the if statements. If we have an hash implementation where key is String and value is function, we can just call something like

function = hash.Get("moscow");    
function(); 

Its complexity is good (theta(log(1))).

Is it possible to do this?

quartz
  • 747
  • 9
  • 26

6 Answers6

4

You can store them in a Map<String, Runnable>. Then with java < 8:

map.put("london", new Runnable() {
    public void run() { functionA(); }
});

Or with java 8, assuming a static method:

map.put("london", YourClass::functionA);

Or with an instance method:

map.put("london", this::functionA);

In all three cases you simply call:

Runnable r = map.get(input.toLowerCase());
if (r != null) r.run();
assylias
  • 321,522
  • 82
  • 660
  • 783
  • 1
    I can try it but just for completeness here can you add the `get` as well in case of Java 8, and how to invoke once you `get` it? – sakura Mar 08 '14 at 20:00
  • Thanks assylias, How can we call the function in your implementation? – quartz Mar 08 '14 at 20:05
  • @assylias Really, even in Java8 its same, the Map, and your example `YourClass` is a Runnable. Right? then `static`.. run() is not static right? – sakura Mar 08 '14 at 20:11
  • 1
    Not that `Runnable.run()` returns `void`. If you want the method to return something you'd use `Callable` – Brian Roach Mar 08 '14 at 20:25
  • @sakura no YourClass can be any class provided that the signature of `functionA` matches the signature of `run` i.e. returns `static void functionA()`. – assylias Mar 09 '14 at 00:29
1

You can use Guava Function as the Hastable value in this case. A better way would be to use Java polymorphism and define this logic (functionA, functionB) in sub-classes:

public interface City {
    public void doSomething();
}

public class Example {

   private Map<String, City> cities;

   public void run(String param) {
       cities.get(param).doSomething();
   }
}

And then you define as many implementations for City as you need (London, Moscow ...) and you add instances of them to the map

hmashlah
  • 144
  • 7
1

in C++, you can use std::map. The code would be something like this-

typedef (void)(*funcPtr)(); //declaring a compatible function pointer

std::map<std::string, funcPtr> myFunctions;

myFunctions["london"]=functionA;
myFunctions["paris"]=functionB;
//etc etc...

//calling the function
string wantedCity="london";
myFunction[wantedCity]();

EDIT: I see you removed C++ from tags. java has a similar container, you could look up it's methods.

Yaniv Nikan
  • 108
  • 1
  • 7
1

This is a perfect opportunity for an enum:

enum City {
    London {

        @Override
        void function() {
            System.out.println("Hello from England");
        }

    },
    Moscow  {

        @Override
        void function() {
            System.out.println("Hello from Russia");
        }

    },
    Delhi {

        @Override
        void function() {
            System.out.println("Hello from India");
        }

    };

    // They ALL must have a `function`.
    abstract void function ();
}

public void test() {
    City.valueOf("Moscow").function();
}
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
0

Yes it is possible, as long as you method returns a value. For example:

public SomeReturnType doSomthing(){
    return someReturnType;
}

and in your hashmap do the following

HashMap<String, SomeReturnType> hm = new HashMap<String, SomeReturnType>();

Boolean is probably the best option when comparing in a method.

Mohammad Najar
  • 2,009
  • 2
  • 21
  • 31
  • THere's no need to create your own class, and actually what you show makes no sense. The standard way of doing this in Java is using the `Callable` interface. – Brian Roach Mar 08 '14 at 19:51
  • I'm not sure how this was relevant. I'm not creating a new class. Just defining a return type (SomeReturnType) just like your V. – Mohammad Najar Mar 08 '14 at 19:52
0

You can use the Java Reflection. Just store the function name as value in the HashMap, then call it byMethod.invoke.

Class.getMethod(String name, Class... parameterTypes)

Method.invoke(Object obj, Object... args)

Jiang
  • 590
  • 2
  • 10