Subtracting/comparing two objects?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
Scoox
Posts: 125
Joined: 11 May 2014, 09:12
Location: China

Subtracting/comparing two objects?

28 Nov 2014, 03:25

I have two arrays Array_A and Array_B. I need a function to generate three arrays, one containing items that only appear in Array_A, one containing items that only appear in Array_B and one containing items that are common to both Array_A and Array_B.

After a bit of thinking I concluded that the quickest way to do this would be to create a clone of each array, delete any common items from both arrays (after copying to a third array to hold common items) and you are left with the differences and the intersection. Here's what I've got so far:

Code: Select all

#NoEnv
#SingleInstance Force

/*
	Common: Apple Banana Melon
	Array_A: Pear Orange Walnut Almond
	Array_B: Peanut Cashew Grape Kiwi
*/

Array_A := ["Apple", "Pear", "Banana", "Orange", "Melon", "Walnut", "Almond"]
Array_B := ["Peanut", "Apple", "Melon", "Cashew", "Banana", "Grape", "Kiwi"]

MyArray := Array_Compare(Array_A, Array_B)

For KeyCompare, ArrayCompare in MyArray
{
	Text .= KeyCompare ":"
	For Key, Item In ArrayCompare
		Text .= " " Item
	Text .= "`n"
}

MsgBox %Text%
Return

Array_Compare(Obj1, Obj2)
{
	Comparison := {}
	Comparison.Obj1 := Obj1.Clone()
	Comparison.Obj2 := Obj2.Clone()
	Comparison.Common := {}

	;Note: Once the object is enumerated, you don't need to worry about whether items are deleted or not.
	For Key1, Item1 In Comparison.Obj1
	{
		For Key2, Item2 In Comparison.Obj2
		{
			If (Item1 = Item2)
			{
				Comparison.Common.Insert(Item1)
				Comparison.Obj1.Remove(Key1)
				Comparison.Obj2.Remove(Key2)
				Break
			}
		}
	}
	Return Comparison
}
This brings me to my next question: Are objects global in nature? I mean, in the above script the object returned by the function Array_Compare() can be accessible from outside the function and is not destroyed as long as there are one ore more references to it.

I find my code tends to be very "verbose" and I often find people here on the forums who come up with smarter ways of doing the same thing, so I am wondering if there is a better way of comparing arrays. Thanks!
User avatar
Scoox
Posts: 125
Joined: 11 May 2014, 09:12
Location: China

Re: Subtracting/comparing two objects?

28 Nov 2014, 04:18

Actually the above code does not work ... crap. If both arrays contain the same data, the results are incorrect. Gonna have to recheck that...
User avatar
Scoox
Posts: 125
Joined: 11 May 2014, 09:12
Location: China

Re: Subtracting/comparing two objects?

28 Nov 2014, 04:47

The problem I am having is this: If my array contains items A, B, C, D, if the current enumerator item is B and I delete B, the next item is no longer C but D, because C no occupies the position of B.
User avatar
joedf
Posts: 8940
Joined: 29 Sep 2013, 17:08
Location: Canada
Contact:

Re: Subtracting/comparing two objects?

28 Nov 2014, 11:00

Objects are not really defined as global variables but they are always passed down by reference, meaning [Byref] function or not, they will both modify the same object. No matter the scope...
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500, NVIDIA GTX 1060 6GB, 2x16GB Kingston FURY Beast - DDR4 3200 MHz | [About Me] | [About the AHK Foundation] | [Courses on AutoHotkey]
[ASPDM - StdLib Distribution] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library]
lexikos
Posts: 9560
Joined: 30 Sep 2013, 04:07
Contact:

Re: Subtracting/comparing two objects?

28 Nov 2014, 19:44

Scoox wrote:This brings me to my next question: Are objects global in nature? I mean, in the above script the object returned by the function Array_Compare() can be accessible from outside the function and is not destroyed as long as there are one ore more references to it.
Objects don't have scope; variables have scope. The object is obviously not tied to the variable, since you can return it. You don't store the object itself inside the variable; just a reference. A reference is just a pointer known to be an object, so its reference count is managed automatically.

It might help to understand what happens behind the scenes:

Code: Select all

y := fn()
MsgBox y: %y%

fn() {
    x := {foo: "bar"}  ; Create an object and store its reference in x.
    ObjAddRef(&x)  ; Create a new "manual" reference.
    MsgBox % "&x: " . &x
    return &x  ; Return the new reference, as a plain pointer.
}

MsgBox % Object(y).foo  ; Convert the pointer to a usable reference, and use it.
Scoox wrote:The problem I am having is this: If my array contains items A, B, C, D, if the current enumerator item is B and I delete B, the next item is no longer C but D, because C no occupies the position of B.
Don't modify the array which you are enumerating. Since you're already making a clone, you could enumerate the original object and modify the clone.

Another common technique is to calculate what changes you're going to make, then make those changes after enumeration finishes. For example, build your array of "common" values during enumeration, then remove those values from both arrays after both for-loops complete.
User avatar
Scoox
Posts: 125
Joined: 11 May 2014, 09:12
Location: China

Re: Subtracting/comparing two objects?

29 Nov 2014, 05:00

Thanks for the info and ideas guys!
User avatar
maestrith
Posts: 825
Joined: 16 Oct 2013, 13:52

Re: Subtracting/comparing two objects?

30 Nov 2014, 06:35

This removes the duplicates from Array_A and Array_B and creates a new object with the values that are in common.

Code: Select all

#SingleInstance,Force
Array_A := ["Apple", "Pear", "Banana", "Orange", "Melon", "Walnut", "Almond"]
Array_B := ["Peanut", "Apple", "Melon", "Cashew", "Banana", "Grape", "Kiwi"]
arrays:=compare(Array_A,Array_B)
for index,value in arrays.both
	MsgBox Values in common %value%
for index,value in arrays.A
	MsgBox Values in Array_A Only %value%
for index,value in arrays.B
	MsgBox Values in Array_B Only %value%
return
compare(a,b){
	both:=[],start:=1
	for index,value in a{
		for index1,value1 in b{
			if (value=value1){
				a.Remove(index),b.Remove(index1)
				both.Insert(value)
			}
		}
	}
	return {A:a,B:b,both:both}
}
John H Wilson III 05/29/51 - 03/01/2020. You will be missed.AHK Studio OSDGUI Creator
Donations
Discord
All code is done on a 64 bit Windows 10 PC Running AutoHotkey x32
millsey
Posts: 1
Joined: 21 Nov 2019, 09:26

Re: Subtracting/comparing two objects?

21 Nov 2019, 09:30

Hi Maestrith

I found a problem in the compare code - when you Remove records from the arrays, the index numbers of the remaining records changes - so we have to restart the search every time we remove a record.

Code: Select all

compare(first,second)
{
    both:=[],start:=1
    a:=first.Clone()
    b:=second.Clone()
    foundone:=1
    while (foundone=1)
    {
        foundone:=0
        for indexa,valuea in a
        {
            for indexb,valueb in b
            {
                if (valuea=valueb and foundone=0)
                {
                    a.Remove(indexa),b.Remove(indexb)
                    both.Insert(valuea)
                    foundone:=1                   
                }
            }
        }
    }
	return, {A:a,B:b,both:both
}
Millsey
Odlanir
Posts: 659
Joined: 20 Oct 2016, 08:20

Re: Subtracting/comparing two objects?

21 Nov 2019, 10:21

Code: Select all

arrA := {}, narrA := {}, arrB := {}, narrB := {}, arrC := {}, narrC := {}
for k,v in ["Apple", "Mango", "Pear", "Banana", "Orange", "Melon", "Walnut", "Almond"]
   arrA[v] := 1
for k,v in ["Peanut", "Apple", "Melon", "Cashew", "Banana", "Grape", "Kiwi"]
   arrB[v] := 1

for k,v in arrA   
   if (!arrB.HasKey(k))
      narrA.push(k)
for k,v in arrB   
   if (!arrA.HasKey(k))
      narrB.push(k)
for k,v in arrA   
   if (arrB.HasKey(k))
      narrC.push(k)
str := "Only in Array A`n"
for k,v in narrA   
   str .= v "`n" 
str .=  "`nOnly in Array B`n" 
for k,v in narrB   
   str .= v "`n" 
str .=  "`nIn both Arrays`n" 
for k,v in narrC   
   str .= v "`n" 

MsgBox %str%
ExitApp
____________________________________________________________________________
Windows 10 Pro 64 bit - Autohotkey v1.1.30.01 64-bit Unicode
User avatar
Chunjee
Posts: 1402
Joined: 18 Apr 2014, 19:05
Contact:

Re: Subtracting/comparing two objects?

24 Nov 2019, 06:53

Scoox wrote:
28 Nov 2014, 03:25
I have two arrays Array_A and Array_B. I need a function to generate three arrays, one containing items that only appear in Array_A, one containing items that only appear in Array_B and one containing items that are common to both Array_A and Array_B.
Requires https://www.npmjs.com/package/biga.ahk

Code: Select all

A := new biga()

Array_A := ["Apple", "Mango", "Pear", "Banana", "Orange", "Melon", "Walnut", "Almond"]
Array_B := ["Peanut", "Apple", "Melon", "Cashew", "Banana", "Grape", "Kiwi"]

; https://biga-ahk.github.io/biga.ahk/#/?id=difference
Only_A := A.difference(Array_A, Array_B)
; => ["Mango", "Pear", "Orange", "Walnut", "Almond"]
Only_B := A.difference(Array_B, Array_A)
; => ["Peanut", "Cashew", "Grape", "Kiwi"]


; https://biga-ahk.github.io/biga.ahk/#/?id=intersection
Common := A.intersection(Array_A, Array_B)
; => ["Apple", "Banana", "Melon"]
ExitApp
john_c
Posts: 493
Joined: 05 May 2017, 13:19

Re: Subtracting/comparing two objects?

25 May 2020, 13:26

@Odlanir Your code works great for me, thanks, but could you explain what is the purpose of arrA[v] := 1 and arrB[v] := 1?

How these lines work? And are these 1 really integers or may be they are actually Booleans?

Code: Select all

; Misleading?
arrA[v] := True
arrB[v] := True
User avatar
Chunjee
Posts: 1402
Joined: 18 Apr 2014, 19:05
Contact:

Re: Subtracting/comparing two objects?

25 May 2020, 15:20

john_c wrote:
25 May 2020, 13:26
@Odlanir Your code works great for me, thanks, but could you explain what is the purpose of arrA[v] := 1 and arrB[v] := 1?
In that example it creates two intermediate arrays where the value is stored as the key arrA[v] := 1 can be thought of as {"Apple": 1}

The two intermediate arrays are then compared by looking up the key "Apple", if that key/value pair is 1, then it does exist as a value in the original array. if (arrB.HasKey(k))


I'm not a big fan of this key as the value trick, because its not very readable. But it can be "faster"

john_c wrote:
25 May 2020, 13:26
And are these 1 really integers or may be they are actually Booleans?
in ahk true and false are indistinguishable with 1 and 0

Code: Select all

var := true
msgbox, % var
; => 1

if (1 == true) {
	msgbox, Hello!
}
john_c
Posts: 493
Joined: 05 May 2017, 13:19

Re: Subtracting/comparing two objects?

25 May 2020, 16:15

Chunjee wrote:
25 May 2020, 15:20
In that example it creates two intermediate arrays where the value is stored as the key arrA[v] := 1 can be thought of as {"Apple": 1}

The two intermediate arrays are then compared by looking up the key "Apple", if that key/value pair is 1, then it does exist as a value in the original array. if (arrB.HasKey(k))
This is excellent explanation, thanks a lot.
Chunjee wrote:
25 May 2020, 15:20
in ahk true and false are indistinguishable with 1 and 0
Yes, but I mean semantic difference. I use 1/0 for real integers only :) From what you said, yes, they are really integers.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Billykid and 224 guests