我如何根据java中的模式匹配在地图中找到一个键
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29523711/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can i find a key in a map based on a pattern matching in java
提问by нα???z
I want to find keys in a map with a pattern matching.
我想在具有模式匹配的地图中找到键。
Ex:-
Map<String, String> map = new HashMap<String, String>();
map.put("address1", "test test test");
map.put("address2", "aaaaaaaaaaa");
map.put("fullname", "bla bla");
From above map, I want to get the values of keys which has prefix of "address". So as in this example output should be the first two results ("address1" and "address2").
从上面的地图中,我想获取前缀为“address”的键的值。所以在这个例子中输出应该是前两个结果(“address1”和“address2”)。
How can I achieve this dynamically?
我怎样才能动态地实现这一点?
Thanks.
谢谢。
回答by Avalanche
Something like this:
像这样的东西:
for (Entry<String, String> entry : map.entrySet()) {
if (entry.getKey().startsWith("address")) {
// do stuff with entry
}
}
回答by Alexis C.
You can grab the keySet
of the map and then filter to get only keys that starts with "address" and add the valid keys to a new Set.
您可以抓取keySet
地图的 ,然后过滤以仅获取以“address”开头的键,并将有效键添加到新的 Set 中。
With Java 8, it's a bit less verbose:
使用 Java 8,它就不那么冗长了:
Set<String> set = map.keySet()
.stream()
.filter(s -> s.startsWith("address"))
.collect(Collectors.toSet());
回答by StackFlowed
You will have to loop through the Key Set and match the pattern
您将必须遍历密钥集并匹配模式
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.
}
回答by Pineechio
If you have Java 8 features, something like this should work:
如果你有 Java 8 特性,这样的事情应该可以工作:
Set<String> addresses = map.entrySet()
.stream()
.filter(entry -> entry.getKey().startsWith("address"))
.map(Map.Entry::getValue)
.collect(Collectors.toSet());
回答by Benjamin Boutier
If you don't need big performance, browsing all the keys on your map (map.entrySet
) to get the ones matching your pattern should be enough.
如果您不需要很大的性能,浏览地图 ( map.entrySet
)上的所有键以获得与您的模式匹配的键就足够了。
If you need good performance, a solution i have used to solve this kind of problem is to use an in-memory database such as H2: you put your data in a memory table, create unique index on the key and you will get good performance for the 2 cases:
如果您需要良好的性能,我用来解决此类问题的解决方案是使用内存数据库,例如 H2:将数据放在内存表中,在键上创建唯一索引,您将获得良好的性能对于 2 种情况:
- Getting a value associated to the key (
select value from in_mem_table where key = ?'
), classic usage of an hashmap - Getting values associated to a "key pattern" (
select value from in_mem_table where key like 'adress%'
)
- 获取与键 (
select value from in_mem_table where key = ?'
)关联的值,哈希图的经典用法 - 获取与“关键模式”(
select value from in_mem_table where key like 'adress%'
)关联的值
回答by MadConan
I created an interface...
我创建了一个界面...
import java.util.Map;
@FunctionalInterface
public interface MapLookup {
<V> List<V> lookup(String regularExpression, Map<String,V> map);
}
And the implementation
和实施
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<>();
}
}
The 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);
}
The result
结果
[-1, 3]
Or maybe that's overkill. I can see a repeated use for this, though.
或者也许这太过分了。不过,我可以看到重复使用它。
For those who want the pre-java8 version:
对于那些想要 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;
}
}
回答by Pedro Silva
One way is to create a function that searches all the map for keys starting with address but that would remove the advantage of the map, since the objective is probably to be fast. Another way is to create a list or array containing all keys starting with address, but that is only worth if you just want the keys starting with address.
一种方法是创建一个函数,在所有地图中搜索以地址开头的键,但这会消除地图的优势,因为目标可能是快速。另一种方法是创建一个包含所有以地址开头的键的列表或数组,但这仅在您只想要以地址开头的键时才有价值。
Now do you need to be able to search for anything or just a specific thing? And do you need the map or can it be another thing like an array or list?
现在您是否需要能够搜索任何内容或仅搜索特定内容?你需要地图还是可以是另一个像数组或列表这样的东西?
回答by aiguy
I came across a similar need and attempted implementing a POC for such a data structure. I came to the conclusion its much more practical to partition data in some manner :)
我遇到了类似的需求,并尝试为这样的数据结构实现 POC。我得出的结论是,以某种方式分区数据更实用:)
However, if you really have your mind set on implementing something like that you would need a structure more similar to a trie tree. Here is what I got (my apologies since the code is in Scala but it can easily be adapted and if you put your mind to it you can probably finish it and make it useable)
但是,如果您真的下定决心要实现类似的东西,您将需要一个更类似于特里树的结构。这是我得到的(我很抱歉,因为代码在 Scala 中,但它可以很容易地进行调整,如果你下定决心,你可能可以完成它并使其可用)
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]) {
}
Basically the idea is we look up every character in a subsequent map the complexity would now be the length of the key. Which, really, should be an acceptable limitation since compilation of a reg ex is likely O(N) anyways. Also in cases where you have shorter keys and many entries would yield much better performance then iterating over all the keys. If you swap the mutable.HashMap with some kind of own implementation with clever hashing and take advantage of the fact that a character is really an int, and in case of ASCII strings (which will likely be the key) actually a short. It would also be more difficult if you're looking up some more complex expression then something*, but still likely doable.
基本上这个想法是我们在随后的映射中查找每个字符,复杂性现在是键的长度。这实际上应该是一个可以接受的限制,因为无论如何编译正则表达式很可能是 O(N)。同样,如果您有较短的键并且许多条目会产生更好的性能,然后迭代所有键。如果您将 mutable.HashMap 与某种自己的具有巧妙散列的实现交换,并利用字符实际上是 int 的事实,并且在 ASCII 字符串(可能是键)的情况下实际上是一个短字符。如果您要查找一些更复杂的表达式然后某事*,这也会更加困难,但仍然可能可行。
edit: a 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"))
}
}
}