如何比较两个列表并找出它们之间的差异?

3
以下函数将新项目列表与旧列表进行比较,并找出差异:
1.已从旧列表中删除的项目 2.添加到新列表中的项目(原始列表中不存在)。
我编写了两个循环来实现这一点,它们产生了以下输出:
oldItems = "an, old, list" ---> Items To Delete: 'an,old' newItems = "a, new, list" ---> Items To Create: 'new'
第一个问题是a应该在要创建的项目中显示,但我认为因为它是an的子字符串,所以没有被拾取。
第二个问题(?)是我做两个循环似乎效率低下。 代码可以重构吗?
public function testList() hint="Compares two lists to find the differences."
{
    local.oldItems = "a, new, list";
    local.newItems = "an, old, list";
    local.toDelete = "";
    local.toCreate = "";

    // Loop over newItems to find items that do not exist in oldItems 
    for (local.i = 1; local.i LTE ListLen(local.newItems, ", "); local.i++)
    {
        if (! ListContains(local.oldItems, ListGetAt(local.newItems, local.i, ", ")))
        {
            local.toCreate = ListAppend(local.toCreate, ListGetAt(local.newItems, local.i, ", "));
        }
    }

    // Loop over old items to find items that do not exist in newItems
    for (local.i = 1; local.i LTE ListLen(local.oldItems, ", "); local.i++)
    {
        if (! ListContains(local.newItems, ListGetAt(local.oldItems, local.i, ", ")))
        {
            local.toDelete = ListAppend(local.toDelete, ListGetAt(local.oldItems, local.i, ", "));
        }
    }

    writeDump(var="Items To Delete: '" & local.toDelete & "'");
    writeDump(var="Items To Create: '" & local.toCreate & "'", abort=true);
}
7个回答

5

是的,我相信你可以重构你的代码。

我更喜欢使用数组函数,因为它进行精确匹配(包括大小写)。这种方法确保了在列表之间选择差异时,"a"被选中。

希望这可以帮到你:

<cfscript>
    oldList = "an, old, list";
    newList = "a, new, list";

    result = compareLists(oldList, newList);

    writeDump(result);

    // -------------------------------------------------------------------------

    public struct function compareLists (
        required string listA,
        required string listB
    ){

        local.a = listToArray(arguments.listA, ',');
        local.b = listToArray(arguments.listB, ',');

        local.itemsNotInListB = [];
        local.itemsNewInListB = [];

        // Compare all items in 'list A' to 'list B'
        for (local.item in local.a) {
            if (!arrayContains(local.b, local.item))
            {
                arrayAppend(local.itemsNotInListB, local.item);
            }
        }
        // Compare all items in 'list B' to 'list A'
        for (local.item in local.b) {
            if (!arrayContains(local.a, local.item))
            {
                arrayAppend(local.itemsNewInListB, local.item);
            }
        }

        return {
             newItems = local.itemsNewInListB
            ,deletedItems = local.itemsNotInListB
        };
    }
</cfscript>

Aaron,这太棒了,谢谢。我认为它对我来说总体上会非常有用。然而,针对我的目的,我想使用一个循环并使用Ray提到的ListFind()函数。我认为你的UDF很棒,但在这种情况下有点过度设计。感谢演示! - Mohamad
没关系。但是,我确实回答了你的问题 :) - Aaron Greenlee
重新查看一下这个.. 运行此代码会出错:您已尝试将类型为coldfusion.runtime.Array的标量变量取消引用为结构 - 看起来for in循环在数组上不起作用 :-? - Mohamad

3

获取正确匹配的答案是使用带有分隔符的ListFind()函数,而不是使用ListContains()函数:

if (! ListFind(local.oldItems, ListGetAt(local.newItems, local.i, ", "), ", ")) {}

必须使用分隔符,否则函数将尝试匹配整个字符串。

没有重构的答案。


3

真的,不要重复造轮子。使用Java Lists或Sets,ColdFusion运行在JVM之上:

<cfscript>
oldItems = "an, old, list"; //Items To Delete: 'an,old'
newItems = "a, new, list"; //Items To Create: 'a,new'
// ArrayList could be HashSet if items in both lists are expected to be unique
oldItems = createObject("java", "java.util.ArrayList").init(listToArray(oldItems, ", "));
newItems = createObject("java", "java.util.ArrayList").init(listToArray(newItems, ", "));

itemsToDelete = createObject("java", "java.util.HashSet").init(oldItems);
itemsToDelete.removeAll(newItems);

itemsToCreate = createObject("java", "java.util.HashSet").init(newItems);
itemsToCreate.removeAll(oldItems);
</cfscript>

<cfoutput>
itemsToDelete: #listSort(arrayToList(itemsToDelete.toArray()),"textNoCase")#<br /><!--- an,old --->
itemsToCreate: #listSort(arrayToList(itemsToCreate.toArray()),"textNoCase")#<!--- a,new --->
</cfoutput>

作为奖励,这里有一份Java代码的链接可以供我参考。

我真的必须接受同时使用Java和Coldfusion。由于我对Java知之甚少,所以不得不使用它有点让人望而却步;然而它似乎非常简单且功能强大。 - Mohamad
1
Bruce Eckel的《Java编程思想》 http://www.amazon.com/Thinking-Java-4th-Bruce-Eckel/dp/0131872486 是学习Java语言的好书。我所知道的最好的ColdFusion -> Java书籍是 Java for ColdFusion Developers http://www.amazon.com/Java-ColdFusion-Developers-Eben-Hewitt/dp/0130461806 - orangepips

3

cflib.org上有3个列表UDFs:

列表比较 - http://cflib.org/udf/listCompare - 将一个列表与另一个列表进行比较,找出第一个列表中不存在于第二个列表中的元素。执行与同名自定义标记相同的功能。

列表差异 - http://cflib.org/udf/ListDiff - 比较两个列表并返回未在两个列表中都出现的元素。

列表差异重复 - http://cflib.org/udf/ListDiffDup - 此函数比较两个列表,并返回包含两个输入列表之间差异的新列表。此函数与ListDiff不同,因为它将列表中的重复元素视为不同的元素。


2

你尝试过搜索CFLib.org吗?那里有多个列表函数,包括一个用于查找差异的函数。至于你在子字符串方面遇到的问题,请阅读ListContains的文档。这就是它应该工作的方式。尝试使用ListFind或ListFindNoCase代替。


1
<cfset strListTupla = "SKU,CANTIDAD,VENTA">
<cfset strListSend = "CANTIDAD,SKU">

<cfset strListSend = ListSort(strListSend, "textnocase", "asc")>
<cfset strListTupla = ListSort(strListTupla, "textnocase", "asc")>

<cfset strListTupla = ListToArray (strListTupla)>
<cfloop index="j" from="1" to="#Arraylen(strListTupla)#">
    <cfoutput>
    <cfif NOT ListFind(strListSend, strListTupla[j])>
        Not Found #strListTupla[j]#
    </cfif><br/>
    </cfoutput>
</cfloop>

通过这样,我可以搜索该项,以查看它是否在列表中,同样也可以显示该元素不存在。


0

这两个循环实际上做的事情是一样的,唯一的区别是列表的位置已经交换了。完全没有必要。你只需要检查一个方向; 旧 -> 新。不需要反过来检查 (旧 <- 新)。

创建两个列表的实例,并将它们通过一个循环发送,检查旧列表是否包含与新项目相等的项。

我不知道用for循环是否适合此目的,因为旧列表中的local.i可能是index[7],而您需要在新列表中检查的完全相同的项可能是index[3],这是在可能的更改之后。


Ziga,问题是我需要识别添加的项目(以创建它们)和被删除的项目,以便删除它们...我想不到不使用两个循环就能完成这个任务的方法... - Mohamad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接