Sign in to follow this  
Followers 0
blindwig

UDF: _Array1PullCommon

5 posts in this topic

#1 ·  Posted (edited)

I wrote a function that takes 2 arrays and returns an array containing all the elements common to both source arrays. It also strips these common elements out of the source arrays.

Sidenote: I'm calling my array UDFs _Array1*, because I deal mostly with 1-based arrays. Some of my functions accept 0-based array input, but always output 1-based arrays.

Here comes the code:

CODE

;===============================================================================

;

; Function Name: _Array1PullCommon()

; Description: Pulls all the common elements out of 2 given arrays and returns an array of these common elements.

; Parameter(s): $A1 and $A2 are 1-dimensional arrays, and $ArrayBase specifys weather they are 0- or 1-based

; Requirement(s):

; Return Value(s): Success: A 1-based array containung the elements common between arrays $a1 and $a2

; Failure: Empty String

; Note: Upon return, $a1 and $a2 will be 1-based, regardless of their base before the function call

; Note: Upon return, $a1 and $a2 will not longer contain the common elements

; Note: Upon return, $a1, $a2, and the returned array will all be sorted

; Author(s): Mike Ratzlaff <mike@ratzlaff.org>

; Revision: 20050622A

;

;===============================================================================

;

;Pulls the common elements out of $a1 and $a2, returns them in an array

;note: on return, all 3 arrays ($a1, $a2, and the returned array) are 1-based arrays

Func _Array1PullCommon(ByRef $a1, ByRef $a2, $ArrayBase = 1, $ProgressTitle = @ScriptName)

Dim $a1ndx, $a2ndx, $a1top, $a2top

;input check

If Not (IsArray($a1) And IsArray($a2)) Then

SetError(1)

Return ''

EndIf

;Setup

If $ArrayBase Then

$ArrayBase = 1

$a1Top = $a1[0]

$a2Top = $a2[0]

Else

$ArrayBase = 0

$a1Top = UBound($a1) - 1

$a2Top = UBound($a2) - 1

EndIf

If $a1top >= UBound($a1) or $a2top >= UBound($a2) Then

SetError(1)

Return ''

EndIf

$a1ndx = $ArrayBase

$a2ndx = $ArrayBase

Dim $a1new[$a1top + 1], $a2new[$a2top + 1]

If $a1top > $a2top Then

Dim $a3new[$a1top]

Else

Dim $a3new[$a2top]

EndIf

If $ProgressTitle <> '' Then ProgressOn($ProgressTitle, 'Comparing Lists...','',-1,-1,16)

If $ProgressTitle <> '' Then ProgressSet(16)

_ArraySort($a1, 0, $ArrayBase, $a1top)

If $ProgressTitle <> '' Then ProgressSet(33)

_ArraySort($a2, 0, $ArrayBase, $a2top)

If $ProgressTitle <> '' Then ProgressSet(50)

;compare arrays side-by-side

While $a1ndx <= $a1Top and $a2ndx <= $a2top

While $a1ndx <= $a1top And $a2ndx <= $a2top And $a1[$a1ndx] < $a2[$a2ndx]

$a1new[0] = $a1new[0] + 1

$a1new[$a1new[0]] = $a1[$a1ndx]

$a1ndx = $a1ndx + 1

WEnd

While $a1ndx <= $a1top And $a2ndx <= $a2top And $a1[$a1ndx] > $a2[$a2ndx]

$a2new[0] = $a2new[0] + 1

$a2new[$a2new[0]] = $a2[$a2ndx]

$a2ndx = $a2ndx + 1

WEnd

If $a1ndx <= $a1top And $a2ndx <= $a2top And $a1[$a1ndx] = $a2[$a2ndx] Then

$a3new[0] = $a3new[0] + 1

$a3new[$a3new[0]] = $a1[$a1ndx]

$a1ndx = $a1ndx + 1

$a2ndx = $a2ndx + 1

EndIf

If $ProgressTitle <> '' Then ProgressSet(50 + (($a1ndx + $a2ndx) * 50) / ($a1Top + $a2Top) )

WEnd

;finish out the arrays

While $a1ndx <= $a1Top

$a1new[0] = $a1new[0] + 1

$a1new[$a1new[0]] = $a1[$a1ndx]

$a1ndx = $a1ndx + 1

If $ProgressTitle <> '' Then ProgressSet(50 + (($a1ndx + $a2ndx) * 50) / ($a1Top + $a2Top) )

WEnd

While $a2ndx <= $a2Top

$a2new[0] = $a2new[0] + 1

$a2new[$a2new[0]] = $a2[$a2ndx]

$a2ndx = $a2ndx + 1

If $ProgressTitle <> '' Then ProgressSet(50 + (($a1ndx + $a2ndx) * 50) / ($a1Top + $a2Top) )

WEnd

;trim the new arrays

ReDim $a1new[$a1new[0] + 1]

ReDim $a2new[$a2new[0] + 1]

ReDim $a3new[$a3new[0] + 1]

If $ProgressTitle <> '' Then ProgressOff()

;return the new arrays

$a1 = $a1new

$a2 = $a2new

Return $a3new

EndFunc

Edited by blindwig

Share this post


Link to post
Share on other sites



Found sound bugs in my logic, fixed the code. Also added an optional progress meter. Edited the above post.

Share this post


Link to post
Share on other sites

How would you change this code so that it returned elements not contained in both?

For example:

$array1 contains 3456, 4567, 5678

$array2 contains 9999, 3456, 4567, 5678, 1111

I would want returned an array with just 9999 and 1111 in it.

Thanks,

-John

Share this post


Link to post
Share on other sites

How would you change this code so that it returned elements not contained in both?

For example:

$array1 contains 3456, 4567, 5678

$array2 contains 9999, 3456, 4567, 5678, 1111

I would want returned an array with just 9999 and 1111 in it.

Thanks,

-John

Sorry this reply is pretty late, but if you still need an answer:

Using code:

$a3=_Array1PullCommon($a1, $a2)

Now $a3 contains a list of common elements, and $a1 and $a2 contain the unique elements. So if you want a list of unique elements, just join or merge the two arrays:

$a4=_ArrayMerge($a1, $a2)

and now $a4 will contain the complete list of unique elements.

Do a search for an array merging routine, I'm sure that there are a few here somewhere...

Share this post


Link to post
Share on other sites

I am getting an error when using this function:

==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.:

$a1new[$a1new[0]] = $a1[$a1ndx]

^ ERROR

before I spend too much time trying to wrap my head around why this is happening, do you know off the top of your head what it may be?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0