【问题标题】:Creating a List of elements from an existing List从现有列表创建元素列表
【发布时间】:2019-03-22 18:21:08
【问题描述】:

我正在创建一个遗传算法来解决一些特定问题。由于这个问题很难描述,我写了一个小例子来说明我在做什么。

我有一个应该随着时间而发展的元素列表。

每个元素都有一个适应度值,它决定了它有多好。这是代表元素的类:

class Element implements Comparable<Element>{
    private int fitness;
    Element( int _fitness){
        this.fitness=_fitness;
    }

    public int getFitness() {
        return fitness;
    }

    @Override
    public int compareTo( Element o ) {
        return this.fitness-o.getFitness();
    }

    @Override
    public String toString() {
        return this.fitness+"";
    }
}

最佳元素是具有最大适应度值的元素。

示例:

list_Iteration_One | list_Iteration_Two| list_Iteration_Three
Element(5)         | Element(9)        | Element(14) 

Element(4)         |Element(5)         | Element(9) 

Element(3)         |Element(5)         | Element(9) 

Element(2)         |Element(4)         | Element(5) 

Element(1)         |Element(3)         | Element(5) 

正如我们所见,程序应该将元素列表作为输入,并进化这些元素以创建一个新列表。

规则是取列表的一半,并合并每两个Elment创建一个新元素。

对于所选元素,它们应该具有最大适应度值。

对于上面的示例,我使用Element(5) + Element(4) 创建Element(9),使用Element(3) + Element(2) 创建Element(5),剩下的我使用Element(5), Element(4), Element(3)

对于第 3 次迭代,我正在做同样的事情等等。

这是我为一次迭代所做的:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class BestDataStructure {

    public static void main( String[] args ) {
        List<Element> list = Stream.of(new Element(5),
                new Element(4),
                new Element(3),
                new Element(2),
                new Element(1)).collect(Collectors.toCollection(ArrayList::new));
        List<Element> theNewList = getTheNewList(list);
        System.out.println(theNewList);
    }

    private static List<Element> getTheNewList( List<Element> list ) {
        List<Element> theNewList = new ArrayList<>();

        int numberOfTimes = list.size()/2;
        Element bestElement=null;
        Element secondBestElement=null;
        for (int i =0; i<numberOfTimes; i++){
            bestElement= Collections.max(list);
            list.remove(bestElement);

            secondBestElement= Collections.max(list);
            list.remove(secondBestElement);

            Element child = new Element(bestElement.getFitness()+secondBestElement.getFitness());
            theNewList.add(child);

            theNewList.add(bestElement);
            theNewList.add(secondBestElement);
        }
        return theNewList;
    }


}

class Element implements Comparable<Element>{
    private int fitness;
    Element( int _fitness){
        this.fitness=_fitness;
    }

    public int getFitness() {
        return fitness;
    }

    @Override
    public int compareTo( Element o ) {
        return this.fitness-o.getFitness();
    }

    @Override
    public String toString() {
        return this.fitness+"";
    }
}

由于我应该处理大小的List(在 2000 到 50000 元素之间),我需要知道处理此类处理的最佳数据结构。

我每次都在ArryList 中寻找最大元素,这是一个非常糟糕的主意。

每次迭代后的结果列表应该与第一个列表具有相同的大小,不幸的是这不是我在getTheNewList 方法中得到的。

我也在寻找什么,我应该如何处理这个任务,我应该在第一时间寻找最好的元素,还是我应该迭代地选择主题......

【问题讨论】:

  • 怎么在第 3 次迭代中,最后三个元素不是 9、5、5?如果我错了,请纠正我,但我的理解是您将最后一个列表中最大的三个元素保留在新列表中?
  • 是的,你是对的,一般来说,如果我有一个包含十个元素的列表,我应该在新一代中有 5 个新元素。对于我的示例,我在列表中有 5 个,但在新列表中有两个新元素。剩下的我应该复制上一代最好的元素。
  • 听起来你想要一个堆,这是由PriorityQueuejava.util包中提供的。
  • @DavidConrad 我也想,我会测试这个实现。

标签: java data-structures collections java-stream genetic-algorithm


【解决方案1】:

您可以使用 Java 流:使用 IntStream 生成元素的前半部分并附加原始列表的前半部分。以下方法需要一个排序列表并返回一个新的排序元素列表:

private static List<Element> getTheNewList(List<Element> elements) {
    int halfElements = elements.size() / 2;
    return Stream.concat(
            IntStream.range(0, halfElements)
                    .mapToObj(index -> new Element(elements.get(index * 2).getFitness() + elements.get(index * 2 + 1).getFitness())),
            elements.stream().limit(halfElements + 1)
    )
            .sorted(Comparator.reverseOrder())
            .collect(Collectors.toList());
}

如果你按照以下方式使用它:

List<Element> iteration1 = Arrays.asList(
        new Element(5),
        new Element(4),
        new Element(3),
        new Element(2),
        new Element(1)
);
System.out.println(iteration1);
List<Element> iteration2 = getTheNewList(iteration1);
System.out.println(iteration2);
List<Element> iteration3 = getTheNewList(iteration2);
System.out.println(iteration3);

这将打印:

[5, 4, 3, 2, 1]
[9, 5, 5, 4, 3]
[14, 9, 9, 5, 5]

【讨论】:

    【解决方案2】:

    我建议确保您的列表在传递给getTheNewList 之类的方法之前按适合度排序,而不是让该方法返回一个新列表,而是让它在同一个列表上运行。例如,如果您的列表按降序排序,您可以简单地取出最后两个元素,因为在这种情况下size of list/2 是 2。然后,从列表中的第一个元素开始组合 2 个一组的元素,并将此列表插入另一个列表。然后,遍历这个组合元素列表,找出这个新元素应该插入到列表中的哪个位置以保持顺序。这是它的样子,

    private void getTheNewList( List<Element> list ) {
        List<Element> theNewList = new ArrayList<>();
        int numberOfTimes = list.size()/2;
        Element bestElement=null;
        Element secondBestElement=null;
        for (int i = 0 ; i < numberOfTimes; i++) {
            //remove last element of the list
            list.remove(list.size() - 1);
            bestElement= list.get(numberOfTimes * 2 - 2);
    
            secondBestElement= Collections.max(numberOfTimes * 2 - 1);
    
            Element child = new Element(bestElement.getFitness()+secondBestElement.getFitness());
            theNewList.add(child);
        }
        //insert combined elements into original list
        for (int i = 0; i < numberOfTimes; i++) {
            for (int j = 0; j < list.size(); j++) {
                if (list.get(j) <= theNewList.get(i)) {
                    list.insert(j, theNewList.get(i));
                    break;
                }
                list.insert(j, theNewList.get(i));
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-04-19
      • 1970-01-01
      • 2013-12-16
      • 1970-01-01
      • 2014-02-10
      • 2015-10-26
      • 1970-01-01
      • 1970-01-01
      • 2018-09-24
      相关资源
      最近更新 更多