当前位置: 首页 > 知识库问答 >
问题:

将复杂的while循环重构为Java 8流

施华奥
2023-03-14

我有一个复杂的实体结构。其中包含上一项的ID(“PreviodeLementId”)

interface IPreviousElementEntity<PK> {
    public void setId(PK id);
    public PK getId();
    public void setPreviousElementId(PK previousElementId);
    public PK getPreviousElementId();
}

从DB接收到所有实体后,我需要将结果列表转换为链表,而链表应由前面的ID组织。

我编写了以下代码进行转换:

static <T extends IPreviousElementEntity> LinkedList<T> getLinkedListByPreviousId(Collection<T> collection) {
    LinkedList<T> linkedList = new LinkedList<>();
    if (collection == null || collection.isEmpty())
        return linkedList;

    // first find root element
    collection.stream()
            .filter(element -> element.getPreviousElementId() == null)
            .forEach(linkedList::add);

    if (linkedList.isEmpty()) return linkedList;

    // TODO: convert to use stream. Please help!
    Boolean isRun = true;
    while (isRun) {
        for (T element : collection) {
            isRun = false;
            if (linkedList.getLast().getId().equals(element.getPreviousElementId())) {
                linkedList.add(element);
                isRun = true;
                break;
            }
        }
    }

    return linkedList;
}

但是这个代码太可怕了!有可能在一个流上编写所有这些转换吗?我特别想摆脱雷鸣般的while循环。

我的完整代码:

import java.util.*;

public class App {
    public static void main(String[] args) {
        Entity entity1 = new Entity(3L, 2L, "third");
        Entity entity2 = new Entity(2L, 1L, "second");
        Entity entity3 = new Entity(4L, 3L, "forth");
        Entity entity4 = new Entity(1L, null, "first");

        List<Entity> entities = new ArrayList<>();
        entities.add(entity1);
        entities.add(entity2);
        entities.add(entity3);
        entities.add(entity4);

        LinkedList<Entity> linkedListByPreviousId = getLinkedListByPreviousId(entities);
        System.out.println(linkedListByPreviousId);
    }

    private static <T extends IPreviousElementEntity> LinkedList<T> getLinkedListByPreviousId(Collection<T> collection) {
        LinkedList<T> linkedList = new LinkedList<>();
        if (collection == null || collection.isEmpty())
            return linkedList;

        // first find root element
        collection.stream()
                .filter(element -> element.getPreviousElementId() == null)
                .forEach(linkedList::add);

        if (linkedList.isEmpty()) return linkedList;

        //TODO: convert to use stream. Please help!
        Boolean isRun = true;
        while (isRun) {
            for (T element : collection) {
                isRun = false;
                if (linkedList.getLast().getId().equals(element.getPreviousElementId())) {
                    linkedList.add(element);
                    isRun = true;
                    break;
                }
            }
        }

        return linkedList;
    }
}

interface IPreviousElementEntity<PK> {
    public void setId(PK id);
    public PK getId();
    public void setPreviousElementId(PK previousElementId);
    public PK getPreviousElementId();
}

class Entity implements IPreviousElementEntity<Long> {
    private Long id;
    private Long previousElementId;
    private String name;

    public Entity(Long id, Long previousElementId, String name) {
        this.id = id;
        this.previousElementId = previousElementId;
        this.name = name;
    }

    @Override
    public Long getId() {
        return id;
    }

    @Override
    public void setId(Long id) {
        this.id = id;
    }

    @Override
    public Long getPreviousElementId() {
        return previousElementId;
    }

    @Override
    public void setPreviousElementId(Long previousElementId) {
        this.previousElementId = previousElementId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Entity entity = (Entity) o;
        return Objects.equals(id, entity.id) &&
                Objects.equals(previousElementId, entity.previousElementId) &&
                Objects.equals(name, entity.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, previousElementId, name);
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Entity{");
        sb.append("id=").append(id);
        sb.append(", previousElementId=").append(previousElementId);
        sb.append(", name='").append(name).append('\'');
        sb.append('}');
        return sb.toString();
    }
}

共有1个答案

仲阳朔
2023-03-14

while循环很糟糕,因为它试图使用列表执行O(n^2)操作,并且不断重复,直到没有更多的选项为止。

通过使用previousElementId作为键的映射,O(n)操作更合适。

if (linkedList.isEmpty()) return linkedList;

//create a map with previousElementId as Key, T as Object
Map<Integer, T> map = collection.stream().collect(
            Collectors.toMap(T::getPreviousElementId, Function.identity()));

//we fetch nodes using the current ID as the key
T node = map.get(linkedList.getLast().getId());
while(node != null) {
    linkedList.add(node);
    node = map.get(node.getId());
}
 类似资料:
  • 作为练习,我将一些旧代码转换为函数流。我对溪流了解不多。看起来转换这段代码应该很简单,但我运气不太好。该方法从给定的整数开始,将其传递给isPrime,如果它是prime,isPrime将返回true。然后将要打印的新(下一个)素数交给用户。如果isPrime为false,则i递增,我们检查下一个整数。

  • while循环开始之前的语句没有打印,并且从1开始没有打印循环中的值。相反,它从一个随机的大int开始打印。

  • 我想知道下面代码的时间复杂度是O(n^3)还是O(n^2)

  • 问题内容: 我正在尝试将此for循环重写为for每个循环。 这就是我尝试过的 谁能指出我正确的方向?谢谢。 问题答案: 我认为您想得太多… :)

  • 在js中,当在forEach函数中遍历arrayitems时,我遇到了一个问题。我只是有一个ID数组,其中一些ID不到10个字符,我想在开头用“0”填充这些字符。示例:在这种情况下,我想用填充最后一项。当然,它也可以在各种其他方式,但我只是不明白为什么它不起作用。 下面是我的代码: