优化两个列表比较

时间:2014-10-01 08:50:51

标签: java performance grails groovy comparison

我有两个来自SQL DB的联系人列表(A和B)。在我的应用程序中,我需要根据联系人姓名显示这些列表的比较表。如果名单A中的联系人存在于列表A但不存在B中,则联系人A的详细信息标记为绿色,并且旁边有空红色空格(对于列表B中缺少的条目。如果联系人姓名存在于B而不是A中,B标记为绿色。如果两个列表中都存在联系人姓名,但地址不同,则两个联系人都标记为黄色。

我正在生成CSV比较和分页界面。

目前,我不太理想的解决方案将首先创建第三个列表,其中包含A和B中的所有联系人姓名,删除重复项。接下来(如果分页)我将应用偏移+大小。最后,在剩下的条目中,我将按联系人名称(从新列表中)搜索A和B,并调用一个比较方法,告诉我要做什么颜色标记。

这对于我获得的数据量是可行的,高达4 -5k,分页延迟2秒。虽然我知道这不是一个理想的解决方案,但想不出更好的解决方案。此外,我还有一些新功能(过滤器更改/添加/删除)将无法使用此方法进行最佳操作。

我可以使用哪种方法来解决这个比较问题?

更新

控制器代码:

    //createCompareList() based on parameters generate HQL query and pull contacts from Contact table 
        def listA = createCompareList(params) 
        def listB = createCompareList(params)

        def unionList = listA.collect{it.details.name}.plus(listB.collect {it.details.name})
        unionList = unionList.unique()
        result.unionListSize = unionList.size()
        unionList.sort()

其余的比较发生在GSP中(这将转移到控制器,并传递需要在GSP中处理更少的内容)

        <table class="table table-bordered">
            <thead>
                <tr> 
                    <th> C

ontact name</th>
                <th> List A </th>
                <th> List B </th>
            </tr>
        </thead>
        <tbody>
            <g:each in="${unionList}" var="unionName">
                <g:set var="listAContact" value="${listA.find {it.details.name.equals(unionName)}}"/>
                <g:set var="listBContact" value="${listB.find {it.details.name.equals(unionName)}}"/>
                <tr>

                    <td>
                    <b>${unionName}</b> 
                    </td>

                    <g:if test="${listAContact}">
                        <g:if test="${listBContact}">
                            <g:if test="${listAContact?.compareTo(listBContact) == 1}">
                                <td class="warning">
                            </g:if>
                            <g:else>
                                <td>
                            </g:else>
                            <g:render template="compare_cell" model="[obj:listAContact]"/>
                            </td>
                        </g:if>
                        <g:else>
                            <td class="danger">
                                <g:render template="compare_cell" model="[obj:listAContact]"/>

                            </td>
                        </g:else>
                    </g:if>
                    <g:else><td></td></g:else>


                    <g:if test="${listBContact}">
                        <g:if test="${listAContact}">
                            <g:if test="${listBContact?.compareTo(listAContact) == 1}">
                                <td class="warning">
                            </g:if>
                            <g:else>
                                <td>
                            </g:else>
                            <g:render template="compare_cell" model="[obj:listBContact]"/>

                            </td>
                        </g:if>
                        <g:else>
                            <td class="success">
                            <g:render template="compare_cell" model="[obj:listBContact]"/>
                            </td>
                        </g:else>
                    </g:if>

                    <g:else><td></td></g:else>

                </tr>

            </g:each>
        </tbody>
    </table>

5 个答案:

答案 0 :(得分:1)

如果要从SQL数据库获取数据,并且联系人列在不同的表中,则可以在表之间执行LEFT JOIN。例如:

SELECT A.*, B.id 
FROM ContactsA A 
LEFT JOIN ContactsB B ON A.id = B.id;

使用jdbc检索其结果。如果联系人出现在列表ContactsAid,则这些结果包含属于ContactsB的所有联系人以及带有NULL的其他列。您可以使用该列来区分两个列表中显示的条目。

修改

如果您的两个列表是从同一个表中提取的,那么您始终可以在同一个表上执行thr LEFT JOIN,从而将将条目拆分为两个列的列进行参数化:

例如,假设您按年龄拆分条目,则查询应为:

SELECT A.*, B.id 
FROM ContactsA A 
LEFT JOIN ContactsA B ON A.id = B.id AND B.age >= 18
WHERE A.age < 18;

结束编辑

如果您无法更改查询,并且已经有两个Java ListAB,则检查联系人是否存在的最佳方式两者都是从较短的列表构建一个集合,并使用该集合来检查较短列表中哪些元素不存在。

答案 1 :(得分:1)

加快2 Lists使用套装的比较。如果您将哈希值用作联系人的名称,则可以在O(1)中检查条目是否在列表中。如果是,请检查其他信息。

Set<Contact> set_a = a.toSet
Set<Contact> set_b = b.toSet
foreach(e in (a union b))
  if(set_a contains e && !set_b contains e)
     //in a but not in b
  else if(!set_a contains e && set_b contains e)
     //in b but not in a
  else
     //in b and in a, check additional information for these elements

应该加速整个事情因为比较便宜得多

这导致比较的O(2n)+构建集合的总体复杂性。 (一次检查e中的e和一次检查e中的e)

答案 2 :(得分:1)

我不确定我是否理解您的要求,但我认为所有这些都可以在数据库结束时进行查询。

据我说,让db处理比jdbc代码快得多的比较。

A和B是联系人列表,在DB中都是表格

Req1:A中的联系人列表,其中没有B

select id  <or required attrib> from A where id not in (select id from B)

这将是仅在A中的id列表,将它们附加到带有绿色的Java列表A中,因为您知道B中没有匹配的条目将B中的相应条目保留为空

Req2:B

中唯一联系人的类似内容
select id  <or required attrib> from B where id not in (select id from A)

两个列表中的内容完全相反,现在将此列表附加到B中,绿色和A中的相应空条目

Req3:两个列表中的ID相同,但addr是差异

select A.id from A,B where A.id=B.id and A.addr<>B.addr

这给出了匹配但具有差异地址的id列表,现在将id附加到两个颜色为黄色的列表

这节省了比较,着色任务在java / pgming语言中有点重。

答案 3 :(得分:0)

我的提示:使用SortedSet作为累加器。因此,您可以将调用保存到unique()sort(),这两个调用都会遍历整个列表:

SortedSet unionList = new TreeList()
for( def a in listA ) unionList << a.details.name
for( def b in listB ) unionList << b.details.name
unionList // now it's unique and sorted in one sit

答案 4 :(得分:0)

我从一开始就没有想到的显而易见的解决方案是使用Contact.name作为密钥从数据库列表创建一个映射。这使得搜索速度更快,并且通过对比较代码的一些更改,我得到了58秒的处理时间到4秒。