【问题标题】:Java: How to convert list to set then compare for missing valuesJava:如何将列表转换为设置然后比较缺失值
【发布时间】:2021-07-22 09:30:54
【问题描述】:

我的目标是使用 Set 定位并打印我的数据中的任何缺失值 界面。

我有一个像下面这样的 POJO


public class Info {

    private final String folder;
    private final String version;
    private final String key;
        
    public static Builder builder() {
        return new Builder();
    }
    
    public static Builder builder(Info info) {
        return new Builder(info);
    }
        
    private Info(Builder builder) {
        this.folder = builder.folder;
        this.version = builder.version;
        this.key = builder.key;
        
    public String getFolder() {
        return folder;
    }
        
    public String getVersion() {
        return version;
    }
        
    public String getCreated() {
        return created;
    }
        
    // toString(), hashCode(), equals()
        
    // Builder class
        
    public Builder withFolder(String folder){
        this.folder = folder;
        return this;
    }

   // withVersion(String version)
   // withKey(String key)


    public Info build(){
        return new Info(this);    
    }

}

使用下面的代码,我从我的数据源创建一个列表。

List<Info> newList = previousList.stream().map(m -> Info.builder()
            .withFolder(m.getFolder())
            .withKey(m.getKey())
            .withVersion(m.getVersion())
            .build())
            .collect(Collectors.toList());

// Printed output is below
list.forEach(System.out::println);

下面是类似于我的列表输出的输出。 显示了两个示例文件夹和两个示例丢失文件。 每个键都有多个版本号。

// Output

[folder=folderA, version=3.48.137, key=fileA-sources.jar]
[folder=folderA, version=3.48.128, key=fileA-sources.jar]
[folder=folderA, version=3.48.125, key=fileA-sources.jar]
[folder=folderA, version=3.48.137, key=fileA-javadoc.jar]
[folder=folderA, version=3.48.128, key=fileA-javadoc.jar]
[folder=folderA, version=3.48.125, key=fileA-javadoc.jar]
[folder=folderA, version=3.48.137, key=fileA.jar]
[folder=folderA, version=3.48.128, key=fileA.jar]

// Missing [folder=folderA, version= 3.48.125, key=fileA.jar]

[folder=folderB, version=1.7.16, key=fileB.pom]
[folder=folderB, version=1.7.14, key=fileB.pom]
[folder=folderB, version=1.7.12, key=fileB.pom]
[folder=folderB, version=1.7.16, key=fileB.jar]
[folder=folderB, version=1.7.14, key=fileB.jar]

// Missing [folder=folderB, version 1.7.12, key=fileB.jar]

下面是我将列表转换为集合的流。

Set<Info> set = list.stream().map(m -> Info.builder()
            .withFolder(m.getFolderKey())
            .withVersion(m.getVersion())
            .withKey(m.getKey())
            .build()).collect(Collectors.toSet());

我的目标是使用 Set 在我的数据中查找和打印任何缺失值。特别是版本号。

我想比较作为 fileA-sources.jar、fileA-javadoc.jar 和 fileA.jar 一部分的版本号,以便找出缺失的部分。有关缺少条目的注释示例,请参见上面的输出。

我的数据包含七种不同的文件类型,并且有许多与上述两种类似的条目。

我对 Java 还很陌生,很可能错过了一些非常基本的东西。我意识到我的计划可能完全不可行,因此我们感谢任何帮助或正确方向的建议。谢谢。

【问题讨论】:

  • 看起来你已经显示了处理的输出,但是没有输入,很难理解你想要什么。您也可以将输入添加到您的问题中吗?
  • 我添加了输入,并希望在键 fileA.ext1、fileA.ext2 等中识别任何缺失的版本号。 fileA.ext1 和 fileA.ext2 应该具有完全相同数量的版本和相应的密钥。所以,我的目标是找到缺失的版本。
  • 我们对您的 ObjectSetObject 课程一无所知。令人惊讶的是,您似乎对同一件事有两个不同的课程。此外,将您自己的类命名为Object 是一个坏主意。然后,当我读到这句话“回顾一下:我想比较任何缺少的键和版本号的键集和版本号”时,我感到很惊讶。你之前没有对这个要求说过任何话,所以“recap”不合适。事实上,那句话之前的冗长内容似乎与您的实际任务完全无关。
  • 感谢您的意见。我会努力澄清我的问题。

标签: java list set java-stream


【解决方案1】:

这还没有完全成熟,但它似乎确实有效。

1:从实际条目中收集一组键

2:从实际条目中收集一组文件夹/版本组合

3:使用收集的密钥和文件夹/版本组合的组合构建一组所需的条目

4:从所需条目中过滤掉实际条目

import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Test {
    Set<FolderEntry> findMissing(Set<FolderEntry> actual) {
        Set<String> keys = actual.stream().map(e -> e.key).collect(Collectors.toSet());

        Set<FolderEntry> folderVersions = actual.stream()
                .map(e -> new FolderEntry(e.folder, e.version, null))
                .collect(Collectors.toSet());

        Set<FolderEntry> missing = folderVersions.stream()
                .flatMap(fv -> {
                    Stream.Builder<FolderEntry> builder = Stream.builder();
                    keys.forEach(key -> builder.accept(new FolderEntry(fv.folder, fv.version, key)));
                    return builder.build();
                })
                .filter(desired -> !actual.contains(desired))
                .collect(Collectors.toSet());
        
        return missing;
    }

    public static void main(String[] args) {
        Set<FolderEntry> folderAEntries = Set.of(
                new FolderEntry("folderA", "3.48.137", "fileA-sources.jar"),
                new FolderEntry("folderA", "3.48.128", "fileA-sources.jar"),
                new FolderEntry("folderA", "3.48.125", "fileA-sources.jar"),
                new FolderEntry("folderA", "3.48.137", "fileA-javadoc.jar"),
                new FolderEntry("folderA", "3.48.128", "fileA-javadoc.jar"),
                new FolderEntry("folderA", "3.48.125", "fileA-javadoc.jar"),
                new FolderEntry("folderA", "3.48.137", "fileA.jar"),
                new FolderEntry("folderA", "3.48.128", "fileA.jar")
                );
        new Test().findMissing(folderAEntries)
                .forEach(System.out::println);

        Set<FolderEntry> folderBEntries = Set.of(
                new FolderEntry("folderB", "1.7.16", "fileB.pom"),
                new FolderEntry("folderB", "1.7.14", "fileB.pom"),
                new FolderEntry("folderB", "1.7.12", "fileB.pom"),
                new FolderEntry("folderB", "1.7.16", "fileB.jar"),
                new FolderEntry("folderB", "1.7.14", "fileB.jar")
                );
        new Test().findMissing(folderBEntries)
                .forEach(System.out::println);
    }

    static class FolderEntry {
        final String folder;
        final String version;
        final String key;

        public FolderEntry(String folder, String version, String key) {
            this.folder = folder;
            this.version = version;
            this.key = key;
        }

        @Override
        public int hashCode() {
            return Objects.hash(folder, key, version);
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            FolderEntry other = (FolderEntry) obj;
            return Objects.equals(folder, other.folder) && Objects.equals(key, other.key)
                    && Objects.equals(version, other.version);
        }

        @Override
        public String toString() {
            return "FolderInfo [folder=" + folder + ", version=" + version + ", key=" + key + "]";
        }
    }
}

输出:

FolderInfo [folder=folderA, version=3.48.125, key=fileA.jar]
FolderInfo [folder=folderB, version=1.7.12, key=fileB.jar]

我一开始误解了你的问题,我最初的回答没有帮助。我把它留在这里作为历史:

如果你已经有一个List&lt;SetObject&gt;,那么你可以通过简单地将列表作为参数传递给Set实现的构造函数来获得一个Set&lt;SetObject&gt;

Set<SetObject> set = new HashSet<>(list);

如果您能进一步解释确定是否缺少某些东西背后的逻辑,我可能会提供进一步的帮助。

【讨论】:

  • 是的。因此,例如,fileA.jar、fileA.pom。 fileA.properties(可能有更多文件,具体取决于文件夹)都应该具有相同的版本号。每个文件有多个版本号,例如 1.2-2.1。丢失文件的示例可能是 key:fileA.jar,版本:1.4。我想找出任何缺少的版本号。
【解决方案2】:

一种方法是根据已知模式generate a full set。之后,遍历初始列表并删除表单full_generated_set 类似元素。 full_generated_set 中剩下的是 missing elements

public class TestFolder {

    public static void main(String[] args) 
    {
        //initial set
        List<FolderData> list = new ArrayList<FolderData>();
        list.add(new FolderData("folderB", "1.7.16", "fileB.pom"));
        list.add(new FolderData("folderB", "1.7.14", "fileB.pom"));
        list.add(new FolderData("folderB", "1.7.12", "fileB.pom"));
        list.add(new FolderData("folderB", "1.7.16", "fileB.jar"));
        list.add(new FolderData("folderB", "1.7.14", "fileB.jar"));
        
        List<String> requiredPattern = new ArrayList<String>();
        requiredPattern.add("pom");
        requiredPattern.add("jar");
        
        Set<String> set = list.stream().filter(t->t.folder.equals("folderB")).
                          map(t->t.version).distinct().
                          collect(Collectors.toSet());
        set.forEach(System.out::println);
        
        //create a full set
        Set<FolderData> fullSet = new HashSet<FolderData>();
        for(String version: set)
        {
            for(String pattern: requiredPattern)
            {
              fullSet.add(new FolderData("folderB",version,"fileB."+pattern));
            }
        }
        
        fullSet.forEach(System.out::println);
        //remove matching elements
        for(FolderData fd:list)
        {
            FolderData remove=null;
            for(FolderData haveFd:fullSet)
            {
                if(fd.folder.equals(haveFd.folder) && fd.version.equals(haveFd.version) && fd.key.equals(haveFd.key))
                {
                    remove = haveFd;
                    break;
                }
            }
            
            if(remove!=null) fullSet.remove(remove);
        }
        System.out.println("missing");
        fullSet.forEach(System.out::println);
        
    }
    
    static class FolderData
    {
        String folder;
        String version;
        String key;
        
        public FolderData(String folder, String version, String key)
        {
            this.folder = folder;
            this.version = version;
            this.key = key;
        }
        
        public String toString()
        {
            return folder+","+version+","+key;
        }
    }
}

一个改进可以是更新requiredPattern,因此不需要手动添加案例。

requiredPattern =list.stream().map(t->t.key).distinct().collect(Collectors.toList());
//also update on generating full set to use the new pattern
fullSet.add(new FolderData("folderB",version,pattern));

输出

//version
1.7.16
1.7.14
1.7.12
//full generated set
folderB,1.7.12,fileB.pom
folderB,1.7.12,fileB.jar
folderB,1.7.16,fileB.jar
folderB,1.7.16,fileB.pom
folderB,1.7.14,fileB.pom
folderB,1.7.14,fileB.jar
//missing
folderB,1.7.12,fileB.jar

【讨论】:

    猜你喜欢
    • 2013-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多