【问题标题】:Randomly selecting a key based on the frequency of a value根据值的频率随机选择一个键
【发布时间】:2013-11-04 15:48:14
【问题描述】:

我有以下哈希图:

Map <Country, List<City>> map = new HashMap<Country, List<City>>();

我想随机选择一组国家,条件如下:城市数量较少的国家应该有较高的被选中概率。

为了解决这个问题,我想我会创建以下地图:

Map <Country, Integer> map = new HashMap<Country, Integer>();

其中整数表示List&lt;City&gt; 的大小。

这样我就可以根据整数值对Map 进行排序,然后选择整数值较低的国家/地区。

但似乎我这样做的时间很长,而且它不是很随机。您对如何有效解决这个问题有什么建议吗?

【问题讨论】:

  • 您只需将TreeMap 与您自己的Comparator 一起使用会自动根据大小对值进行排序吗?
  • 你指的这个T和List是什么?请从我们的角度重新阅读您的帖子(因为您没有发布任何代码而没有看到您的代码的人),并对其进行编辑,以使一切都一清二楚。
  • map get/put 粗略来说需要 O(1),所以你用额外的 map 来保持值频率的想法看起来并不是“很长的路要走”
  • @JoshM 谢谢这是个好主意。
  • @RegUser "所以 List 的大小越小,它被选中的可能性就越大。"这是什么意思?你的问题有点迟钝,因为你从不解释你在做什么。您只是在寻找城市数量最少的国家吗?上面的引用表明可能不是,但不清楚。

标签: java hashmap frequency-analysis


【解决方案1】:

这里与遗传算法中使用的技术类似,称为the roulette wheel selection

实现起来非常简单:

  1. 创建一个国家数组,其大小是所有国家/地区的整数总和
  2. 将每个国家 N 次放入数组中,其中 N 是城市的数量
  3. 在数组中随机选择一个值

国家/地区将以其城市数量的概率被选中

编辑:如果城市数量非常多,您可以通过除以最低城市数量来标准化数字,以便每个国家/地区都保留在表格中。

【讨论】:

  • 这使得城市数量较多的国家被选中的可能性更高。我希望正好相反,这样城市数量较少的国家就有很高的被选中的可能性。
  • 也许反转数字然后乘以 100?因为你最终会得到一个小于 1 的数字?
  • 我刚刚意识到这不是一个好主意,因为我的一些值 = 0 并且您不能除以 0。那么还有其他不涉及反转的方法吗?
  • 反转和乘法是反转过程的好方法。关于零值,如果将所有值都加 1,它会如何变化?
  • 顺便说一句,如果最高值和最低值之间的差异太大,导致几乎没有选择低概率国家,请不要犹豫,使用 log 或 sqrt 函数来减少间隔。跨度>
【解决方案2】:

我想选择一组城市数量最少的国家/地区。

然后你想要一个List 的国家顺序或城市数量。为什么不创建一个包含 List 城市的 Country

public class Country{
   private final List<String> cityNames = new ArrayList<String>();
   private String name;
   public Country(String n) { name = n; }
   public void addCity(String name){ 
       cityNames.add(name);   // omitting validation
   }
   public List<String> getCityNames(){
       List<String> newList = new ArrayList<String>();
       newList.addAll(cityNames);
       return newList;
   }
   public int numberOfCities(){ 
       return cityNames.size(); 
   }

   public String getName() { return name; }

   @Override
   public String toString(){
      return name + ": Number of Cities = " + cityNames.size();
   }
}

现在您可以像这样根据城市数量对国家/地区列表进行排序

... // inside some method

        Collections.sort(countries, new Comparator<Country>() {
        @Override
        public int compare(Country o1, Country o2) {
            if(o1.numberOfCities() < o2.numberOfCities()){
                return -1;
            }
            if(o1.numberOfCities() > o2.numberOfCities()){
                return 1;
            }
            return 0;
        }
    });

我刚刚使用以下方法对此进行了测试(注意:我向 Country 添加了一个“toString()”方法)

public static void main(String[] args) {
    Country usa = new Country("USA");
    Country canada = new Country("Canada");
    Country brazil = new Country("Brazil");
    usa.addCity("Lansing");
    usa.addCity("New York");
    usa.addCity("Los Angeles");
    usa.addCity("Houston");

    canada.addCity("Toronto");

    canada.addCity("Niagra");

    brazil.addCity("Vila Velha");
    brazil.addCity("Rio");
    brazil.addCity("Barbacena");

    List<Country> countries = new ArrayList<Country>();
    countries.add(usa);
    countries.add(brazil);
    countries.add(canada);
    System.out.println("\n\nAfter Sorting...");
    it = countries.iterator();
    while(it.hasNext()){
        System.out.println(it.next());
    }
    Collections.sort(countries, new Comparator<Country>() {
        @Override
        public int compare(Country o1, Country o2) {
            if(o1.numberOfCities() < o2.numberOfCities()){
                return -1;
            }
            if(o1.numberOfCities() > o2.numberOfCities()){
                return 1;
            }
            return 0;
        }
    });

    System.out.println("\n\nAfter Sorting...");
    it = countries.iterator();
    while(it.hasNext()){
        System.out.println(it.next());
    }

}

还有输出

 Before sorting....
 USA: Number of Cities = 4
 Brazil: Number of Cities = 3
 Canada: Number of Cities = 2


 After Sorting...
 Canada: Number of Cities = 2
 Brazil: Number of Cities = 3
 USA: Number of Cities = 4

【讨论】:

  • “地图是一个排序的集合。”取决于实施。例如 LinkedHashMap 维护一个插入顺序。
  • 排序后你是否只使用 Math.Random 如果数字 0.8 你使用最后 50 个中的随机索引%?
  • @RegUser:如果这对你有用,当然可以。有很多选择。但是拥有一个排序列表可以让您专注于索引而不是城市规模。
  • @MadConan 我已经实现了这个,但我不允许遍历集合。我需要对数据进行采样。有没有有效的抽样方法?谢谢
  • @RegUser:我不确定你的意思。
猜你喜欢
  • 1970-01-01
  • 2013-08-27
  • 2013-03-22
  • 2011-02-15
  • 1970-01-01
  • 2013-10-14
  • 1970-01-01
  • 2012-02-22
  • 2019-07-30
相关资源
最近更新 更多