在 ArrayList 中查找最常见的随机分配字符串



我正在研究一个模拟器,其中Person对象(存储在ArrayList中("繁殖"并产生婴儿,它们继承"基因",表示为4个字母的字符串。在程序开始时,随机生成第一个人的基因库。

在计时器的每个滴答声中,我都想计算所有 Person 对象中最常见的"基因"是什么。

这四个字母是:
1. G, Z, N, F
2.A, T, C,
G 3.B, F, Q,
N 4.A, C, T, E

在这种情况下,有 256 种可能的组合,并且必须有一个比 256 个 if-else 语句更有效的检查。

Person 类(减去获取/设置方法(

public class Person {
static Random rand = new Random();
private Person mother;
private Person father;
private String genes;
private char sex;
private int age, numKids;
public Person() {
mother = null;
father = null;
genes = createGenes();
if (rand.nextDouble() <= 0.5)
sex = 'm';
else
sex = 'f';
age = 18;
numKids = 0;
}
public Person(Person m, Person f) {
mother = m;
father = f;
genes = inheritGenes(m, f);
if (rand.nextDouble() <= 0.5)
sex = 'm';
else
sex = 'f';
age = 0;
}
//create genes for original Persons
private String createGenes() {
String genetics = "";
double first = rand.nextDouble();
double second = rand.nextDouble();
double third = rand.nextDouble();
double fourth = rand.nextDouble();
if (first <= 0.25)
genetics += "G";
else if (first <= 0.68)
genetics += "Z";
else if (first <= 0.9)
genetics += "N";
else
genetics += "F";
if (second <= 0.65)
genetics += "A";
else if (second <= 0.79)
genetics += "T";
else if (second <= 0.85)
genetics += "C";
else
genetics += "G";
if (third <= 0.64)
genetics += "B";
else if (third <= 0.95)
genetics += "F";
else if (third <= 0.98)
genetics += "Q";
else
genetics += "N";
if (fourth <= 0.37)
genetics += "A";
else if (fourth <= 0.58)
genetics += "C";
else if (fourth <= 0.63)
genetics += "T";
else
genetics += "E";
return genetics;
}
//inherit genes from parents for new Persons
public String inheritGenes(Person m, Person f) {
String genetics = "";
double first = rand.nextDouble();
double second = rand.nextDouble();
double third = rand.nextDouble();
double fourth = rand.nextDouble();
if (first < 0.5) {
genetics += m.getGenes().charAt(0);
} else
genetics += f.getGenes().charAt(0);
if (second < 0.5) {
genetics += m.getGenes().charAt(1);
} else
genetics += f.getGenes().charAt(1);
if (third < 0.5) {
genetics += m.getGenes().charAt(2);
} else
genetics += f.getGenes().charAt(2);
if (fourth < 0.5) {
genetics += m.getGenes().charAt(3);
} else
genetics += f.getGenes().charAt(3);
return genetics;
}
}

List<Person>中查找最常见基因的示例代码。我刚刚为genesString添加了一个 getter:

String getGenes() {
return genes;
}

代码如下:

List<Person> people = new ArrayList<>();
for (int i = 0; i < 100; i++) {
people.add(new Person()); // 100 random genes
}
String mostCommonGene = people.stream()
.map(Person::getGenes)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.max(Comparator.comparingLong(Map.Entry::getValue))
.get()
.getKey();
System.out.println("Most common gene: " + mostCommonGene);

我们使用Java 8 Streams:

  • 我们得到了people列表的stream()
  • 我们map()(转换(每个PersonString- 他们的genes.
  • 我们collect()基因流groupingBy()Function.identity()Collectors.counting()喂养。此步骤生成一个表示genes及其频率映射Map<String, Long>。实际上,这计算了people列表中基因的出现次数。
  • 然后我们在该地图上调用entrySet(),然后再次stream()- 现在我们有一组映射条目(您可以将它们视为对 - 基因及其在一个对象内的频率。方便(。
  • 我们调用max()来查找具有最高(解释为频率(的条目Comparator.comparingLong()告诉max()算法我们如何比较这些对,但并不s - 这就是为什么我们必须告诉它如何将条目转换为long- 我们得到该条目的值。
  • 然后我们调用get(),因为max()返回一个Optional<T>。我们只想要T(条目(。
  • 最后,我们在代表一对最常见基因及其频率的条目上调用getKey()。如前所述,关键是基因,值是它的频率。

如果你不熟悉这个答案中描述的大多数概念,我强烈建议你学习Java 8 Streams。一旦你习惯了它们,你就无法停止。

根据使用场景,使用额外的Map<String,Long>作为每个基因的计数器(增加每个新人基因的计数器(可能更有效。

这种方法将使用更多的内存(Map<String,Long>最多256个元素(,新的Person构建会慢一些(Map的更新(,但是如果有许多Person对象活着,则在每个刻度上获得最常见的基因可能会快得多,因为这些对象已经在Map中分组和计数, 因此,最多只能比较 256 个条目。

最新更新