简体   繁体   English

如何根据java 8中的值合并对象的ArrayList?

[英]How to merge ArrayList of Objects based on value in java 8?

I want to DB connections in a list from various sources.我想在来自各种来源的列表中建立数据库连接。 Some sources may/may not provide the Url.某些来源可能/可能不提供 URL。

I want to keep the records which has the complete info(ie dbName, connUrl, isActive) + if any db doesn't have the complete record with any of the sources.我想保留具有完整信息的记录(即 dbName、connUrl、isActive)+ 如果任何数据库没有任何来源的完整记录。

Record.java,记录.java,

String dbName;
String connUrl;
String isActiveYN;

MainApp.java,主应用程序.java,

List <Record> connRecords = new ArrayList<>();
connRecords = someFunc(sourceName) // some func takes source as param and returns connection List
connRecords.addAll(someFunc(sourceName));
connRecords.addAll(someFunc(sourceName));
//logic for getting all unique DBs

Eg: List 1 from Source Alpha: [{A,Y},{B,Y},{C, Y},{D,Y}]例如:来自源 Alpha 的列表 1:[{A,Y},{B,Y},{C, Y},{D,Y}]

List 2 from Source Beta: [{A, abc-url, Y}, {B, xyz-url, Y}]源 Beta 中的列表 2:[{A, abc-url, Y}, {B, xyz-url, Y}]

List 3 from Source Gamma: [{A,Y},{C,Y}]源 Gamma 中的列表 3:[{A,Y},{C,Y}]

After merging all the list we get:合并所有列表后,我们得到:

I/P List: [{A,Y}, {B,Y}, {C, Y}, {D,Y}, {A, abc-url, Y}, {B, xyz-url, Y}, {A,Y}, {C,Y}] I/P 列表:[{A,Y}, {B,Y}, {C, Y}, {D,Y}, {A, abc-url, Y}, {B, xyz-url, Y}, {A,Y}, {C,Y}]

for dbName A, source Beta has the complete record info , so we'll take that对于 dbName A,源 Beta 具有完整的记录信息,因此我们将采用

for dbName B, source Beta has the complete record info, so we'll take that对于 dbName B,源 Beta 具有完整的记录信息,因此我们将采用

for dbName C, even none of the sources have the complete info, still we'll keep it since it's an available DB and some source might have the url connection at some point in future.对于 dbName C,即使没有一个来源有完整的信息,我们仍然会保留它,因为它是一个可用的数据库,并且某些来源可能在未来的某个时候具有 url 连接。 for dbName D, even none of the sources have the complete info, still we'll keep it since it's an available DB and some source might have the url connection at some point in future.对于 dbName D,即使没有一个来源有完整的信息,我们仍然会保留它,因为它是一个可用的数据库,并且某些来源可能在未来的某个时候具有 url 连接。

Required O/P List: [{A,abc-url,Y}, {B,xyz-url,Y}, {C,Y},{D,Y}]所需的 O/P 列表:[{A,abc-url,Y}, {B,xyz-url,Y}, {C,Y},{D,Y}]

Can anyone suggest a java 8 way (using streams) way of doing this?任何人都可以建议使用 java 8 方式(使用流)来执行此操作吗?

old school way of doing this:这样做的老派方式:

Map<String, Record> map = new HashMap<>();

        for (Record record: recordList) {
            String dbName = record.getDBName();
            String isActiveYN = record.getIsActiveYN();
            if (map.containsKey(dbName)) {
                if(record.getConnURL() != null)
                  map.replace(dbName, record);
            } else {
                map.put(dbName, record);
            }
        }

List<Record> merged = new ArrayList<>(map.values());

It can be implemented using by implementing a couple of merge functions:它可以通过实现几个merge函数来实现:

  1. merge two Record instances into one将两个Record实例合并为一个
  2. merge two String instances into one将两个String实例合并为一个
  3. override toString method to provide desired output覆盖toString方法以提供所需的输出
  4. fix setting of isActiveN : if merge needed, then set to Y修复isActiveN设置:如果需要合并,则设置为Y
// using Lombok annotations for brevity
@Data
@AllArgsConstructor
@EqualsAndHashCode
class Record {
    String dbName;
    String connUrl;
    String isActiveYN;

    Record merge(Record other) {
        if (this.dbName.equals(other.dbName)) {
            this.connUrl = merge(this.connUrl, other.connUrl);
            this.isActiveYN = "Y"; // if merge called, there are at least two entries
        }
        return this;
    }

    static String merge(String thiss, String thats) {
        return thiss == null ^ thats == null ? (thiss == null ? thats : thiss) : thiss;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        String sep = "";
        if (null != dbName) {
            sb.append(dbName);
            sep = ", ";
        }
        if (null != connUrl) {
            sb.append(sep).append(connUrl);
            sep = ", ";
        }
        if (null != isActiveYN) {
            sb.append(sep).append(isActiveYN);
        }
        sb.insert(0, '{');
        sb.append('}');
        return sb.toString();
    }
}

Then the records may be merged as simply as using Collectors.toMap collector and pass reference to Record::merge as the third parameter:然后可以像使用Collectors.toMap器一样简单地合并记录,并将对Record::merge引用作为第三个参数传递:

// Source Alpha
List<Record> connRecords = new ArrayList<>(Arrays.asList(
        new Record("A", null, "N"),
        new Record("B", null, "Y"),
        new Record("C", null, null),
        new Record("D", null, "N")
));

// Source Beta
connRecords.addAll(Arrays.asList(
        new Record("A", "abc-url", null),
        new Record("B", "xyz-url", "N")
));

// Source Gamma
connRecords.addAll(Arrays.asList(
        new Record("A", null, "N"),
        new Record("C", null, "N")
));

List<Record> merged = new ArrayList<>(
        connRecords.stream()
                   .collect(Collectors.toMap(Record::getDbName, rec -> rec, Record::merge))
                   .values()
);
System.out.println(merged);

Output:输出:

[{A, abc-url, Y}, {B, xyz-url, Y}, {C, Y}, {D, N}]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM