web-dev-qa-db-fra.com

Comment puis-je trouver une clé dans une carte basée sur un modèle correspondant en java

Je veux trouver des clés dans une carte avec un motif correspondant.

Ex:-   
    Map<String, String> map = new HashMap<String, String>();
    map.put("address1", "test test test");
    map.put("address2", "aaaaaaaaaaa");
    map.put("fullname", "bla bla");

De la carte ci-dessus, je veux obtenir les valeurs des clés qui ont le préfixe "adresse". Ainsi, comme dans cet exemple, les deux premiers résultats ("adresse1" et "adresse2") doivent être générés.

Comment puis-je y parvenir de manière dynamique?

Merci.

15
нαƒєєz

Vous pouvez récupérer la keySet de la carte, puis filtrer pour n’obtenir que les clés commençant par «adresse» et ajouter les clés valides à un nouvel ensemble.

Avec Java 8, c'est un peu moins bavard:

Set<String> set = map.keySet()
                     .stream()
                     .filter(s -> s.startsWith("address"))
                     .collect(Collectors.toSet());
15
Alexis C.

Si vous avez des fonctionnalités Java 8, cela devrait fonctionner:

    Set<String> addresses = map.entrySet()
                               .stream()
                               .filter(entry -> entry.getKey().startsWith("address"))
                               .map(Map.Entry::getValue)
                               .collect(Collectors.toSet());
7
Pineechio

Quelque chose comme ça:

    for (Entry<String, String> entry : map.entrySet()) {
        if (entry.getKey().startsWith("address")) {
            // do stuff with entry
        }
    }
5
Avalanche

Vous devrez parcourir le jeu de clés et faire correspondre le motif

for(String key : map.keySet()) {
   if(! key.startsWith("address")) {
       continue;
   }

   // do whatever you want do as key will be match pattern to reach this code.
}
2
StackFlowed

J'ai créé une interface ...

import Java.util.Map;

@FunctionalInterface
public interface MapLookup {
    <V> List<V> lookup(String regularExpression, Map<String,V> map);
}

Et la mise en place

import Java.util.ArrayList;
import Java.util.List;
import Java.util.Map;
import Java.util.regex.Pattern;
import Java.util.stream.Collectors;

public class MapLookupImpl implements MapLookup {
    @Override
    public <V> List<V> lookup(String regularExpression, Map<String, V> map) {
        final Pattern pattern = Pattern.compile(regularExpression);
        List<String> values  = map.keySet()
                .stream()
                .filter(string -> pattern.matcher(string).matches())
                .collect(Collectors.toList());
        if(values!= null && !values.isEmpty()){
            return values.stream().map((key) -> map.get(key)).collect(Collectors.toList());

        }
        return new ArrayList<>();
    }
}

Le test

public static void main(String[] args){

    Map<String, Integer> map = new HashMap<>();
    map.put("foo",3);
    map.put("bar",42);
    map.put("foobar",-1);

    MapLookup lookup = new MapLookupImpl();

    List<Integer> values = lookup.lookup("\\woo\\w*",map);

    System.out.println(values);
}

Le résultat

[-1, 3]

Ou peut-être que c'est exagéré. Je peux voir une utilisation répétée pour cela, cependant.

Pour ceux qui veulent la version antérieure à Java8:

    public class PreJava8MapLookup implements MapLookup {
    @Override
    public <V> List<V> lookup(String regularExpression, Map<String, V> map) {
        Matcher matcher = Pattern.compile(regularExpression).matcher("");
        Iterator<String> iterator = map.keySet().iterator();
        List<V> values = new ArrayList<>();
        while(iterator.hasNext()){
            String key = iterator.next();
            if(matcher.reset(key).matches()){
                values.add(map.get(key));
            }
        }
        return values;
    }
}
1
MadConan

Je suis tombé sur un besoin similaire et j'ai tenté de mettre en place un POC pour une telle structure de données. Je suis arrivé à la conclusion qu'il est beaucoup plus pratique de partitionner les données d'une manière ou d'une autre :)

Cependant, si vous avez vraiment l’intention de mettre en place une telle solution, vous aurez besoin d’une structure plus semblable à un arbre à trois. Voici ce que j’ai eu (mes excuses car le code est en Scala, mais il peut être facilement adapté et si vous le souhaitez, vous pouvez probablement le terminer et le rendre utilisable)

    package component.datastructure

import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer

class RegExpLookup[T] {

  private val root = new mutable.HashMap[Char, Node]

  def put(key: String, value: T): Unit = {
    addNode(key.toCharArray, 0, root, value)
    println(root.toString)
  }

  private def addNode(key: Array[Char], charIdx: Int,
                      currentRoot: mutable.Map[Char, Node], value: T): Unit = {
    if (charIdx < key.length - 1) {
      if (currentRoot.contains(key(charIdx))) {
        addNode(key, charIdx + 1, currentRoot(key(charIdx)).nodeRoot, value)
      } else {
        val node = Node(null, new mutable.HashMap[Char, Node])
        currentRoot.put(key(charIdx), node)
        addNode(key, charIdx + 1, node.nodeRoot, value)
      }
    } else {
      currentRoot.put(key(charIdx), Node(value, null))
    }
  }

  private def getAll(lastNode: Node, buffer: ArrayBuffer[T]): Unit = {
    if (lastNode.value != null)
      buffer.append(lastNode.value.asInstanceOf[T])
    if (lastNode.nodeRoot != null)
      lastNode.nodeRoot.values.foreach(e => {
        getAll(e, buffer)

      })

  }

  def get(key: String): Iterable[T] = {
    val t = findLastNode(key.toCharArray, 0, root)
    println("getting from " + root)
    val isLast = t._2
    if (isLast) {
      val v = t._1.value
      if (v != null)
        return List(v.asInstanceOf[T])
      else
        return null
    } else {
      val buffer = new ArrayBuffer[T]()
      getAll(t._1, buffer)
      return buffer.toList
    }
  }

  private def findLastNode(key: Array[Char], charIdx: Int,
                           root: mutable.Map[Char, Node]): (Node, Boolean) = {
    if (charIdx < key.length - 2 && (key(charIdx + 1) != '*')) {
      return (root(key(charIdx)), false)
    } else if (charIdx < key.length - 1) {
      return findLastNode(key, charIdx + 1, root(key(charIdx)).nodeRoot)
    } else
      return (root(key(charIdx)), true)
  }
}

case class Node(value: Any, private[datastructure] val nodeRoot: mutable.HashMap[Char, Node]) {

}

Fondamentalement, l’idée est que nous examinons chaque caractère d’une carte ultérieure, la complexité étant désormais la longueur de la clé. Ce qui, en réalité, devrait constituer une limite acceptable, étant donné que la compilation d’un enregistrement est probablement O(N) de toute façon. De même, dans le cas où vous avez des clés plus courtes et que de nombreuses entrées donnent de bien meilleures performances que de parcourir toutes les clés. Si vous permutez le mutable.HashMap avec une sorte d'implémentation propre avec un hachage intelligent et tirez parti du fait qu'un caractère est vraiment un int, et dans le cas où ASCII (ce sera probablement la clé) en fait un court. Ce serait également plus difficile si vous recherchiez une expression plus complexe que quelque chose *, mais qui reste probablement faisable.

edit: un test

class MySpec extends PlaySpec {

  val map = new RegExpLookup[String]()

  "RegExpLookup" should {

    "put a bunch of values and get all matching ones" in {
      map.put("abc1", "123")
      map.put("abc2", "456")
      map.put("abc3", "789")
      val result = map.get("abc*")
      println(result)
      val s = result.toSet
      assert(s.contains("123"))
      assert(s.contains("456"))
      assert(s.contains("789"))
    }

    "put a single value and get it by exact key" in {
      map.put("abc", "xyz")
      val result = map.get("abc")
      println(result)
      assert(result.head.equals("xyz"))
    }
  }

}
1
aiguy

Si vous n'avez pas besoin de grandes performances, parcourir toutes les touches de votre carte (map.entrySet) pour obtenir celles qui correspondent à votre modèle devrait suffire.

Si vous avez besoin de bonnes performances, une solution que j'ai utilisée pour résoudre ce type de problème consiste à utiliser une base de données en mémoire telle que H2: vous mettez vos données dans une table mémoire, créez un index unique sur la clé et obtenez de bonnes performances. pour les 2 cas:

  • Obtenir une valeur associée à la clé (select value from in_mem_table where key = ?'), utilisation classique d'un hashmap
  • Obtention de valeurs associées à un "modèle de clé" (select value from in_mem_table where key like 'adress%'
0
Benjamin Boutier

Une solution consiste à créer une fonction qui recherche dans toute la carte les clés commençant par adresse, mais qui supprime l’avantage de la carte car l’objectif est probablement d’être rapide . Une autre méthode consiste à créer une liste ou un tableau contenant clés commençant par adresse, mais cela ne vaut que si vous voulez juste les clés commençant par adresse.

Maintenant, avez-vous besoin de pouvoir rechercher quelque chose ou juste un objet spécifique? Et avez-vous besoin de la carte ou cela peut-il être autre chose qu'un tableau ou une liste?

0
Pedro Silva