如何判断2个数组是否共享同一个元素

时间:2010-06-16 17:28:12

标签: arrays excel vba excel-vba element

所以这是我问题的一个简单形式。 可以说我有2个阵列。 A = {1,2}且B = {2,4,6}。 如果A和B共享一个元素,那么从B中删除该元素。 我知道你可以循环并将A中的每个元素与B中的每个元素进行比较,但必须有更好的方法!

5 个答案:

答案 0 :(得分:4)

如果对数组进行排序(或者您可以对数组进行排序),则可以同时处理两个数组。从两个数组的开头开始直到你将其中一个指针推进到其各自数组的末尾之外:

  • 如果< b然后前进一个指针
  • 如果a = b,则删除b
  • 处的元素
  • 如果a> b然后前进b指针

答案 1 :(得分:2)

你必须编写代码,但它不一定是一个强力的双嵌套循环,你不必从数组中删除任何杂乱的单个元素。

如果添加对Microsoft Scripting Runtime的引用(来自VBE中的“工具”菜单),则可以使用Dictionary对象来简化此操作。它有'存在','删除'和'键'的方法。所以你可以遍历B并在Dictionary中添加元素作为键,然后遍历A,检查这些元素是否存在,如果存在,则删除它们。

作为伪代码:

for each elem in b
    dict(elem)=0 
next elem

for each elem in a
    if dict.exists(elem)
        dict.remove(elem)
    end if
next elem

return dict.keys

如果有的话,上述方法也会删除B中的重复项。

如果您知道您的数组没有错误值作为元素,您也可以使用MATCH(以及VBA'Application.Match'或'Application.WorksheetFunction.Match')。做点什么

=MATCH({2,4,6},{1,2},0)

将返回{2,#N / A,#N / A}。 #N / A的任何位置都是B中不在A中的元素的位置。如果在工作表中进行匹配,则可以拖动公式,如

=IF(ISNA(cell of match),corresponding cell of B,NA())

然后从中过滤出#N / As。在VBA中,你可以做(​​更多伪代码):

matches=application.match(b,a,0) 

for each elem in matches
    if iserror(elem)
        add corresponding element of b to result
    end
next elem

redim result to new smaller size

return result

当然,你必须担心数组起始界限等。

答案 2 :(得分:1)

基于jtolle伪代码的完整且说明完整的VBA解决方案

    Sub ExampleCall()
    Dim a, b: a = Array(1, 2): b = Array(2, 4, 6)
    Debug.Print "Array b: {" & Join(b, ",") & "}";  ' show original array b
    
    '~~~~~~~~~~~~~~~~~~~~~~~~
    'remove duplicates from b via Application.Index()
    '~~~~~~~~~~~~~~~~~~~~~~~~
    b = getUniques(a, b)                            ' << help function getUniques()
    
    Debug.Print " ~~> {" & Join(b, ",") & "}"       ' Array b: {2,4,6} ~~> {4,6}
    End Sub

通过1行getUniques()的帮助功能Application.Match()

// 编辑 2020-07-24由于@jtolle的评论,更正了数组边界:

    Function getUniques(a, b)
    'Purpose: get 1-based items of array b not matching with array a items
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    'a) match array b items against array a
    '   results in a 1-based array {2,#N/A,#N/A}, where
    '   the 1st numeric element of b equalling 2 indicates to be the 2nd item of b and
    '   error elements indicate unique items in b with no duplicate in b
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Dim matches: matches = Application.Match(b, a, 0)   ' results in 1-based array with b dimensions
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    'b) get 1-based unique items in array b
    '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Dim i As Long, ii As Long                           ' counters
    For i = 1 To UBound(matches)                        ' loop through matches
        If IsError(matches(i)) Then                     ' no match #N/A indicates unique item in b
            ii = ii + 1                                 ' increment new counter
            ''matches(ii) = b(i - IIf(LBound(b), 0, 1)) ' OP: get b items to maintain
              matches(ii) = b(i + LBound(b) - 1)        ' edited: get b items to maintain

        End If
    Next i
    ''ReDim Preserve matches(LBound(b) To ii - IIf(LBound(b), 0, 1)) ' OP: reduce to needed size and original boundaries
    ReDim Preserve matches(LBound(b) To ii + LBound(b) - 1) ' edited; reduce to needed size and original boundaries

    getUniques = matches                                ' return function result

    End Function

答案 3 :(得分:0)

不,我没想到。你必须循环。

答案 4 :(得分:0)

如果数组中的值对于其数组是唯一的,则可以使数组索引实际值,从而允许您直接搜索其索引,而不是扫描整个数组。

从具有较少元素的数组开始,我假设你想要做excel / VB?我做了一张照片来说明这个想法。

http://img694.imageshack.us/img694/1503/hackmap.jpg

不是有两个嵌套循环,而是有一个循环,它只迭代最小数组的次数。