Hey, Scripting Guy! Question

Hey, Scripting Guy! I have a dumb question for you: If I have two lists how can I verify that all the items in list 2 can be found in list 1?

-- SS

SpacerHey, Scripting Guy! AnswerScript Center

Hey, SS. Trust us; we’ve heard sillier questions. For example, awhile back the Scripting Son came downstairs on a Saturday morning to find the Scripting Dad eating breakfast. “What’s that?” he said, pointing to his father’s bowl.

“Oatmeal.”

“Isn’t oatmeal supposed to have milk on it?” asked the Scripting Son.

“Regular oatmeal, like the kind Grandma makes, does,” said the Scripting Dad. “But this is instant oatmeal: you just add hot water to instant oatmeal.”

“Oh,” said the Scripting Son. “Maybe that’s why I don’t like instant oatmeal.”

As it turns out years ago, when he was little, the Scripting Son decided to make himself some instant oatmeal. He took the package out of the box, poured it into a bowl, then added cold milk. Not too surprisingly, he didn’t really like it.

Note. No, the Scripting Dad didn’t poke fun at the Scripting Son. After all, the Scripting Dad didn’t want to be reminded of the time he and the Scripting Son were driving home from a baseball game when the Scripting Dad was suddenly struck by a terrible thought. “Uh-oh,” he said as they cruised down the road. “I can’t remember whether or not I took my keys out of the bat bag.”

“You mean the keys you used to start the car, the ones that are in the ignition right now?” asked the Scripting Son.

Yes, those keys.

Needless to say, SS, when it comes to the silliest questions of all time, well, yours just doesn’t stack up all that well. However, and if it’s any consolation, your question has officially become one of the questions answered in this column:

Const TextMode = 1

arrList1 = Array("a","b","c","d","e","f")
arrList2 = Array("a","b","e","g","h")

Set objDictionary = CreateObject("Scripting.Dictionary")
objDictionary.CompareMode = TextMode

For Each strValue in arrList1
    If Not objDictionary.Exists(strValue) Then
        objDictionary.Add strValue, strValue
    End If
Next

For Each strValue2 in arrList2
    If Not objDictionary.Exists(strValue2) Then
        strNotFound = strNotFound & strValue2 & vbCrLf
    End If
Next

If strNotFound <> "" Then
    Wscript.Echo "Items in list 2 that are not in list 1:" & vbCrLf & strNotFound 
End If

Let’s see if we can figure out how this works. The script starts out by defining a constant named TextMode and setting the value to 1; we’ll use this constant later on to tell our Dictionary object to perform case-insensitive searches. We do that because, by default, the Dictionary object sees A (uppercase) and a (lowercase) as totally separate items. If you’d prefer to do a case-sensitive search (where a and A are considered different characters), then leave out this line and the line of code where we configure the CompareMode property.

Note. And if you’d like to know more about the difference between case-sensitive and case-insensitive searches, take a peek at the scripting puzzle Everyone is Special … Except You, James.

After defining the constant we then set up two very simple arrays, arrays that represent our two lists. The array arrList1 consists of the following items:

a
b
c
d
e
f

Meanwhile, the array arrList2 consists of these items:

a
b
e
g
h

Our task is to figure out whether there are any items in arrList2 that are not in arrList1.

How do we plan on doing that? Why, by using the Scripting.Dictionary object, of course. That’s why we use these two lines of code to create an instance of the Dictionary object and then set the CompareMode to the constant TextMode (which will result in case-insensitive searches):

Set objDictionary = CreateObject("Scripting.Dictionary")
objDictionary.CompareMode = TextMode

Good question: why are we using the Dictionary object anyway? We opted to go this route primarily because it’s very tedious to search for specific items in a VBScript array. Suppose we want to know if the value z appears in the array. We can’t just say, “Hey, array: do you have a z anywhere?” Instead, we have to loop through and individually check each item in that array. And then we have to repeat that process for the next value, and the value after that, and – well, you get the idea. With the Dictionary object, however, we can just ask it whether or not it has any z’s, a process we’ll explain momentarily.

Before we can do that, however, we need to grab all the elements in arrList1 and get them into the Dictionary. That’s what these lines of code are for:

For Each strValue in arrList1
    If Not objDictionary.Exists(strValue) Then
        objDictionary.Add strValue, strValue
    End If
Next

As you can see, all we’re doing here is looping through the collection of values stored in the array arrList1. For each of these values we then use the Exists method to determine whether or not the value is already in the Dictionary:

If Not objDictionary.Exists(strValue) Then

Is that important? Well, it could be; after all, the Dictionary object won’t accept duplicate entries. Because the best way to avoid duplicate entries is to check each value before we add it to the Dictionary we use the following line of code to determine whether or not our Dictionary object already has an entry for a, the first item in arrList1:

If Not objDictionary.Exists(strValue) Then

Yes, we know: the syntax – If Not objDictionary.Exists(strValue) – is a little clumsy. But all we’re saying is this: let us know if you don’t have an entry for the letter a. If you already have a key named a that’s fine; we’ll just loop around and check the next item in the list. If you don’t have an a, then we’re going to use this line of code to add a to the Dictionary, setting both the Dictionary key and value to, well, a:

objDictionary.Add strValue, strValue

Note. What’s the difference between a Dictionary key and a value? Tsk, tsk, tsk: you haven’t been reading Sesame Script each month, have you?

When we’re all done our Dictionary will include the following items, which just happen to be the same items found in arrList1:

a
b
c
d
e
f

We’re now ready to start looping through the items in the second list (arrList2) and determine whether or not those items can be found in arrList1. To do that we set up another For Each loop, this one looping through the array arrList2:

For Each strValue2 in arrList2
    If Not objDictionary.Exists(strValue2) Then
        strNotFound = strNotFound & strValue2 & vbCrLf
    End If
Next

Nothing too fancy here, either. Again, we’re using the Exists method to determine whether or not the first value in arrList2 can be found in the Dictionary. As it turns out, the first value (a) actually does exist in the Dictionary. That means that a must also exist in arrList1, which, in turn, means we don’t care about it. (Remember, we’re only looking for items in arrList2 that aren’t in arrList1.) With that in mind, we loop around and try the next item in the list.

Eventually we’re going to run into an item – g – that isn’t in the Dictionary. That will trigger this line of code:

strNotFound = strNotFound & strValue2 & vbCrLf

Here we’re assigning a value to a variable named strNotFound. To be more precise, we’re assigning this variable its existing value (which, at the start of the script, is nothing) plus the value of the item we failed to find in the Dictionary (g) plus a carriage return-linefeed (vbCrLf). In other words, after failing to find g in the Dictionary, strNotFound will be equal to this:

g

We then loop around and try the next item in the list; that’s h, which doesn’t appear in the Dictionary either. We thus append this value and a carriage return-linefeed to the existing value of strNotFound, meaning strNotFound is now equal to this:

g
h

You get the idea. If there were more values in arrList2 we’d simply continue this process until we’ve tested for the existence of each and every one.

And then what happens, after we’ve tested each and every one of those values? This happens:

If strNotFound <> "" Then
    Wscript.Echo "Items in list 2 that are not in list 1:" & vbCrLf & strNotFound 
End If

Here we’re simply checking the value of strNotFound. If strNotFound is an empty string that means that all the values in arrList2 were found in arrList1; therefore, we don’t do anything. If strNotFound is not an empty string that means we found at least one value in arrList2 that doesn’t appear in arrList1. Consequently, we echo back a message similar to this:

Items in list 2 that are not in list 1:
g
h

Needless to say, g and h just happen to be the two items in list 2 that don’t appear in list 1. Pretty cool, huh?

We hope that helps, SS. And remember, there’s no such thing as a dumb question, not even the age-old query, “Does this dress make me look fat?” The truth is, that question isn’t dumb; what’s dumb would be giving an honest and thoughtful answer to that question. (Not that any of the Scripting Guys have ever done that, mind you.)