我有一张桌子,上面有一百个'记录,其中字段与基于id的类似字段配对。我想知道什么是一个好的数据结构,用于保持一对出现在一起的次数的频率计数,而不管它们出现的顺序。
示例数据:
ID Feature 5 F1 5 F2 6 F1 6 F2 7 F3 7 F1 7 F2 8 F1 9 F1 10 F1
示例输出为:
F1 F2 F3 F1 0 3 1 F2 3 0 1 F3 1 1 0
一种选择是对所有特征进行排序并使用二维int数组来表示成对数据,但是数组的2/3是无用/重复的。例如array[i][i] = 0
和array[i][j] = array[j][i]
。鉴于我有数百个功能,这种方法不会起作用。
我想过使用地图,但是密钥需要代表一对,例如(F1,F3)。我也希望有其他解决方案。如果没有,我会使用地图。
答案 0 :(得分:2)
创建一个类,说MyPair
用于存储商品对的哈希键,并覆盖Object#equals(...)
(和Object#hashCode()
),这样订单就不会出现问题(例如通过按字典顺序排序)。
创建Map<MyPair,Integer>
以存储对的频次数。
class MyPair {
public final String feature1;
public final String feature2;
public MyPair(String s1, String s2) {
// Order features so comparison is order-independent.
if (s1.compareTo(s2) <= 0) { // TODO: null check
feature1 = s1;
feature2 = s2;
} else {
feature1 = s2;
feature2 = s1;
}
}
@Override public int hashCode() {
return (s1 + s2).hashCode(); // TODO: cache for performance.
}
@Override public boolean equals(that) {
return (that instanceof MyPair)
&& (that.feature1.equals(this.feature1))
&& (that.feature2.equals(this.feature2));
}
}
然后可以按预期散列对:
Map<MyPair,Integer> freq = new HashMap<MyPair,Integer>();
MyPair pair1 = new MyPair("F1", "F2");
freq.get(pair1); // => null
freq.put(pair1, 1);
MyPair pair2 = new MyPair("F2", "F1");
freq.get(pair2); // => 1
答案 1 :(得分:0)
这是一个简单的算法。我假设数据最初是排序的。它可能写得不像我想要的那样好,但它必须只显示正确的路径:))
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class NeighborListExample {
static class Pair {
private String feature;
private int cnt = 1;
Pair(String feature) {
this.feature = feature;
}
void incr() {
cnt++;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((feature == null) ? 0 : feature.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Pair other = (Pair) obj;
if (feature == null) {
if (other.feature != null)
return false;
} else if (!feature.equals(other.feature))
return false;
return true;
}
@Override
public String toString() {
return "(" + feature + ", " + cnt + ")";
}
}
static Map<String, List<Pair>> feature2neighbors = new HashMap<>();
private static int getId(Object[][] data, int i) {
return ((Integer) data[i][0]).intValue();
}
private static String getFeature(Object[][] data, int i) {
return data[i][1].toString();
}
private static void processFeatures(String[] array) {
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length; j++) {
if (i != j) {
List<Pair> pairs = feature2neighbors.get(array[i]);
if (pairs == null) {
pairs = new LinkedList<>();
feature2neighbors.put(array[i], pairs);
}
Pair toAdd = new Pair(array[j]);
int index = pairs.indexOf(toAdd);
if (index == -1) {
pairs.add(toAdd);
} else {
pairs.get(index).incr();
}
}
}
}
}
static void print(Map<String, List<Pair>> feature2neighbors) {
StringBuilder builder = new StringBuilder();
for (Map.Entry<String, List<Pair>> e : feature2neighbors.entrySet()) {
builder.append(e.getKey()).append(" -> ");
Iterator<Pair> it = e.getValue().iterator();
builder.append(it.next().toString());
while(it.hasNext()) {
builder.append(" ").append(it.next().toString());
}
builder.append("\n");
}
System.out.println(builder.toString());
}
public static void main(String[] args) {
//I assume that data is sorted
Object[][] data = { { 5, "F1" }, //
{ 5, "F2" }, //
{ 6, "F1" }, //
{ 6, "F2" }, //
{ 7, "F3" }, //
{ 7, "F1" }, //
{ 7, "F2" }, //
{ 8, "F1" }, //
{ 9, "F1" }, //
{ 10, "F1" }, //
};
List<String> features = new LinkedList<>();
int id = getId(data, 0);
for (int i = 0; i < data.length; i++) {
if (id != getId(data, i)) {
processFeatures(features.toArray(new String[0]));
features = new LinkedList<>();
id = getId(data, i);
}
features.add(getFeature(data, i));
}
print(feature2neighbors);
}
}
输出:
F1 -> (F2, 3) (F3, 1)
F3 -> (F1, 1) (F2, 1)
F2 -> (F1, 3) (F3, 1)