Creating and manipulating dictionaries

I occasionally use dictionaries in my scripts but only in bits and pieces. So, just for learning purposes, I created a rudimentary database which I’ve included below.

I am not satisfied with the script segment entitled “Modify a dictionary by key value”. It works but I would like to eliminate the repeat loop. Also, I was unable to get the last script segment to work with a compound predicate and resorted to the use of two separate predicates. Thanks for any suggestions.

-- Revised 2022.05.19 to correct issues

use framework "Foundation"
use scripting additions

-- Create a mutable array of mutable dictionaries
set personList to {{firstname:"John", lastname:"Adams", age:60, occupation:"President"}, {firstname:"Samuel", lastname:"Adams", age:70, occupation:"Statesman"}, {firstname:"Thomas", lastname:"Jefferson", age:60, occupation:"President"}}
set personArray to current application's NSMutableArray's arrayWithArray:personList

-- Add a dictionary
set newRecord to {firstname:"Samuel", lastname:"Chase", age:80, occupation:"Supreme Court Justice"}
personArray's addObject:newRecord
set personList to personArray as list

-- Modify a dictionary by key value 
set searchKey to "lastname"
set searchValue to "Chase"
set revisedData to {age:50, occupation:"Founding Father"}
set thePredicate to current application's NSPredicate's predicateWithFormat:"%K == %@" argumentArray:{searchKey, searchValue}
set theDictionary to personArray's filteredArrayUsingPredicate:thePredicate
if theDictionary's |count|() ≠ 1 then error "Multiple or no matches found"
(theDictionary's objectAtIndex:0)'s addEntriesFromDictionary:revisedData
set personList to personArray as list

-- Get dictionaries by key value (occupation in this case)
set searchKey to "occupation"
set searchValue to "President"
set thePredicate to current application's NSPredicate's predicateWithFormat:"%K == %@" argumentArray:{searchKey, searchValue} -- from Shane
set searchResults to (personArray's filteredArrayUsingPredicate:thePredicate) as list

-- Get dictionaries by two key values (firstname and lastname in this case)
set searchKeyOne to "firstname"
set searchValueOne to "Samuel"
set searchKeyTwo to "lastname"
set searchValueTwo to "Adams"
set thePredicate to current application's NSPredicate's predicateWithFormat:"%K == %@ AND %K == %@" argumentArray:{searchKeyOne, searchValueOne, searchKeyTwo, searchValueTwo}
set searchResults to (personArray's filteredArrayUsingPredicate:thePredicate) as list

Is there some reason you didn’t use a predicate?

Your argumentArray should be a flat array, not an array of subarrays:

set thePredicate to current application's NSPredicate's predicateWithFormat:"%K == %@ AND %K == %@" argumentArray:{searchKeyOne, searchValueOne, searchKeyTwo, searchValueTwo}

Thanks Shane. The predicate you suggest for my last script segment works great, and I’ve incorporated that in my first post above.

As regards my script segment entitled “Modify a dictionary by key value”, the following does seem to work without a repeat loop. The fact that this involves an array of mutable dictionaries, and that I am editing an individual dictionary and not the dictionary as part of the array remains a source of some confusion, but I’ll give this some thought.

use framework "Foundation"
use scripting additions

-- Create a mutable array of mutable dictonaries
set personList to {{firstname:"John", lastname:"Adams", age:60, occupation:"President"}, {firstname:"Samuel", lastname:"Adams", age:70, occupation:"Statesman"}, {firstname:"Thomas", lastname:"Jefferson", age:60, occupation:"President"}}
set personArray to current application's NSMutableArray's arrayWithArray:personList

-- Modify a dictionary by key value 
set searchKey to "firstname"
set searchValue to "John"
set revisedData to {age:70, occupation:"Founding Father"}
set thePredicate to current application's NSPredicate's predicateWithFormat:"%K == %@" argumentArray:{searchKey, searchValue} -- from Shane
set theDictionary to (personArray's filteredArrayUsingPredicate:thePredicate)'s objectAtIndex:0
theDictionary's addEntriesFromDictionary:revisedData
set personList to personArray as list --> {{age:70, lastname:"Adams", occupation:"Founding Father", firstname:"John"}, {age:70, lastname:"Adams", occupation:"Statesman", firstname:"Samuel"}, {age:60, lastname:"Jefferson", occupation:"President", firstname:"Thomas"}}

Remember that these variables are just pointers to values – in this case, the same value.

Thanks Shane–that makes sense. I’ve modified my script in post 1 to reflect this method to modify a dictionary.