我想创建一个大范围地图,将符合其编号的密钥映射到存储桶,例如:
NavigableMap<String, String> map = new TreeMap<>();
map.put("var2#" + 0L, "out0"); // "var2#0..100 => out0
map.put("var2#" + 100L, "out1"); // "var2#100..200" => out1
map.put("var2#" + 200L, "out2"); // "var2#200..300" => out2
map.put("var2#" + 300L, "out3"); // "var2#300..+" => out3
这意味着如果新密钥以值res到达,则应为"var2#150" ==> "out1"
我尝试做的是使用有序地图,一切都在使用地图内的数字范围
类似的东西:
String out1 = map.floorEntry("var2#" + 150L).getValue(); //out1 , works!
,但是如果发送var2#2000,而不是获得res“out3”,我得到“out2”,依此类推......
String res = map.floorEntry("var2#" + 2000L).getValue();
Syso(res) ==> out2 , BUT I expected result => "out3"
// because it is bigger that the range.
P.S:
It is very large map with prefix of some "string" and comes after typed
long number . Eg. "var1#100, var1#200 , ...bla1#1000 , bla5#2000....
另一个问题 - 当我在不同的键上有相同的长值时,我希望在字符串上进行第一次匹配,然后在数字上进行...
map.put("var1#" + 200L, "out0");
map.put("var2#" + 200L, "out1");
map.put("var3#" + 200L, "out2");
map.put("var4#" + 200L, "out3");
String out1 = map.floorEntry("var2#" + 150L).getValue();
System.out.println("====> " + out1); //expected out1 , because only match of "var2
String out3 = map.floorEntry("var2#" + 250L).getValue(); //expected out1 , because only match of "var2
System.out.println("====> " + out3);" ....
请问任何建议,也许是一些算法?
答案 0 :(得分:2)
比较字符串前缀,然后在数字上比较后缀的一种方法是:
public static int compareParts(String a, String b) {
final int aLen = a.length(), bLen = b.length(), l = Math.min(aLen, bLen);
int ix = 0;
stringPart: {
for(; ix < l; ix++) {
char aCh = a.charAt(ix), bCh = b.charAt(ix);
int cmp = Character.compare(aCh, bCh);
if(cmp != 0)
return aCh == '#'? -1: bCh == '#'? +1: cmp;
if(aCh == '#') break stringPart;
}
return 0;
}
// number part
int aIx = ix+1, bIx = aIx;
while(aIx < aLen && a.charAt(aIx)=='0') aIx++;
while(bIx < bLen && b.charAt(bIx)=='0') bIx++;
int cmp = Integer.compare(aLen-aIx, bLen-bIx);
for(; cmp == 0 && aIx < aLen; aIx++, bIx++) {
cmp = Character.compare(a.charAt(aIx), b.charAt(bIx));
}
return cmp;
}
但是由于比较方法可能经常被调用,即使单个查找可能涉及多次比较,因此即使代码看起来更复杂,也值得研究一段时间来提高性能:
String.compareTo
这只会对字符串进行一次传递。首先,它会像'#'
那样迭代字符串的第一个字符,停留在第一个不匹配字符或'#'
字符处。如果只有一个字符串遇到'#'
,另一个字符串有更长的前缀,我们必须考虑结果。
只有当两个字符串具有相同的前缀时,才会处理NavigableMap<String, String> map = new TreeMap<>(MyClass::compareParts);
map.put("var2#" + 0L, "out0");
map.put("var2#" + 100L, "out1");
map.put("var2#" + 200L, "out2");
map.put("var2#" + 300L, "out3");
String out1 = map.floorEntry("var2#" + 150L).getValue();
System.out.println("out1 = "+out1);
String out3 = map.floorEntry("var2#" + 2000L).getValue();
System.out.println("res = "+out3);
之后的数字部分。如果有一些,我们不会执行完整的整数解析,而是跳过所有前导零。然后,如果剩余重要部分的长度不同,则它已经指示哪个数字更大。只有当重要部分具有相同的长度时,我们才需要迭代它们。但是我们可以逐字地比较数字,而不需要在这种情况下将它们解释为数字,因为迭代顺序已经从最高有效数字到最低有效数字。
任何一种方法都可以像
一样使用import numpy as np
import matplotlib.pyplot as plt
# Read your file properly
with open('00001.txt', 'r') as f
# Retrieve the data without '\n' code (it was your problem)
data = f.read().splitlines()
# Load it in numpy
a = np.array(data)
# Do what you want with it
yvec1 = a.astype(int)
答案 1 :(得分:1)
问题是TreeMap
正在使用String进行比较。因此按字母顺序排序,var2#2000
介于var2#200
和var2#300
之间。您应该specify a custom comparator,或使用Long
或Integer
作为TreeMap
的密钥。所以,这应该有效:
NavigableMap<Long, String> map = new TreeMap<>();
map.put(0L, "out0"); // "var2#0..100 => out0
map.put(100L, "out1"); // "var2#100..200" => out1
map.put(200L, "out2"); // "var2#200..300" => out2
map.put(300L, "out3"); // "var2#300..+" => out3
答案 2 :(得分:1)
您可以提取密钥的第二部分并将其用作可导航地图的比较器:
Comparator.comparingLong(key -> Long.parseLong(key.split("#")[1]))
所以:
NavigableMap<String, String> map =
new TreeMap<>(Comparator.comparingLong(key -> Long.parseLong(key.split("#")[1])));
map.put("var2#" + 0L, "out0"); // "var2#0..100 => out0
map.put("var2#" + 100L, "out1"); // "var2#100..200" => out1
map.put("var2#" + 200L, "out2"); // "var2#200..300" => out2
map.put("var2#" + 300L, "out3"); // "var2#300..+" => out3
assertThat(map.floorEntry("var2#" + 150L).getValue()).isEqualTo("out1");
assertThat(map.floorEntry("var2#" + 2000L).getValue()).isEqualTo("out3");
答案 3 :(得分:1)
我会拆分密钥以获得每个变量Map
的范围:
Map<String, Ranges> map;
我们实施Ranges
的地方,因为我们需要映射价值和结果,例如Hari Menon提出的。
class Ranges {
NavigableMap<Long, String> map = new TreeMap<>();
public String setFloor(long l, String s){
return map.put(l, s);
}
public String getFloor(long l){
return map.floorEntry(l).getValue();
}
}
这将很容易填充:
Map<String, Ranges> map = new HashMap<>();
Ranges r = new Ranges();
r.setFloor(0L, "out1");
r.setFloor(100L, "out2");
map.put("var1", r);
r = new Ranges();
r.setFloor(0L, "out3");
r.setFloor(100L, "out4");
map.put("var2", r);
System.out.println(map.get("var1").getFloor(50L));
System.out.println(map.get("var2").getFloor(150L));
OUT1
OUT4
我们可以使用NavigableMap
代替HashMap
,但我没有看到这一点。
请注意,这不是NPE安全的,但这并不能确保解决方案简短易读。