用于保持成对数据的频率计数的数据结构?

时间:2014-07-31 20:22:31

标签: java arrays algorithm data-structures

我有一张桌子,上面有一百个'记录,其中字段与基于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] = 0array[i][j] = array[j][i]。鉴于我有数百个功能,这种方法不会起作用。

我想过使用地图,但是密钥需要代表一对,例如(F1,F3)。我也希望有其他解决方案。如果没有,我会使用地图。

2 个答案:

答案 0 :(得分:2)

  1. 创建一个类,说MyPair用于存储商品对的哈希键,并覆盖Object#equals(...)(和Object#hashCode()),这样订单就不会出现问题(例如通过按字典顺序排序)。

  2. 创建Map<MyPair,Integer>以存储对的频次数。

  3. 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)