Category talk:Wren-maputil: Difference between revisions
Content added Content deleted
(Added source code for new 'Wren-maputil' module.) |
m (→Source code: Now uses Wren S/H lexer.) |
||
(3 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
===Source code=== |
===Source code=== |
||
< |
<syntaxhighlight lang="wren">/* Module "maputil.wren" */ |
||
import "./check" for Check |
import "./check" for Check |
||
Line 17: | Line 17: | ||
} |
} |
||
// Creates a new Map from a |
// Creates a new Map from a sequence of keys and assigns |
||
// the same value to all of them. |
// the same value to all of them. |
||
static createSame(keys, value) { |
static createSame(keys, value) { |
||
Check. |
Check.seq("keys", keys) |
||
var m = {} |
var m = {} |
||
for (key in keys) m[key] = value |
for (key in keys) m[key] = value |
||
Line 27: | Line 27: | ||
// Adds entries to an existing Map from lists of keys and values |
// Adds entries to an existing Map from lists of keys and values |
||
// which must be of the same length |
// which must be of the same length. |
||
// Keys which are already present in the Map have their values replaced |
|||
static addAll(map, keys, values) { |
|||
// if 'replace' is true but not otherwise. |
|||
Check.map("map", map) |
|||
// Returns the Map after the additions. |
|||
static addAll(map, keys, values, replace) { |
|||
Check.map("map", map) |
|||
Check.list("keys", keys) |
Check.list("keys", keys) |
||
var count = keys.count |
var count = keys.count |
||
Check.list("values", values, count, count) |
Check.list("values", values, count, count) |
||
Check.bool("replace", replace) |
|||
for (i in 0...count) map[keys[i]] = values[i] |
|||
for (i in 0...count) { |
|||
if (!replace && map.containsKey(key[i])) continue |
|||
map[keys[i]] = values[i] |
|||
} |
|||
return map |
return map |
||
} |
} |
||
// Adds entries to an existing Map from a |
// Adds entries to an existing Map from a sequence of keys and assigns |
||
// the same value to all of them |
// the same value to all of them. |
||
// Keys which are already present in the Map have their values replaced |
|||
static addAllSame(map, keys, value) { |
|||
// if 'replace' is true but not otherwise. |
|||
// Returns the Map after the additions. |
|||
static addAllSame(map, keys, value, replace) { |
|||
Check.map("map", map) |
Check.map("map", map) |
||
Check. |
Check.seq("keys", keys) |
||
Check.bool("replace", replace) |
|||
for (key in keys) map[key] = value |
|||
for (key in keys) { |
|||
if (!replace && map.containsKey(key)) continue |
|||
map[key] = value |
|||
} |
|||
return map |
return map |
||
} |
} |
||
// |
// Merges all the elements of map2 into map1. |
||
// Keys which are already present in map1 have their values replaced |
|||
// if 'replace' is true but not otherwise. |
|||
// Returns map1 after the additions. |
|||
// A specialized version of 'addAll'. |
|||
static merge(map1, map2, replace) { |
|||
Check.map("map1", map) |
|||
Check.map("map2", map) |
|||
for (key in map2.keys) { |
|||
if (!replace && map1.containsKey(key)) continue |
|||
map1[key] = map2[key] |
|||
} |
|||
return map |
|||
} |
|||
// Returns true if all keys in the 'keys' sequence are keys of an existing Map |
|||
// or false otherwise. |
// or false otherwise. |
||
static containsAll(map, keys) { |
static containsAll(map, keys) { |
||
Check.map("map", map) |
Check.map("map", map) |
||
Check. |
Check.seq("keys", keys) |
||
for (key in keys) { |
for (key in keys) { |
||
if (!map[key]) return false |
if (!map[key]) return false |
||
Line 57: | Line 86: | ||
} |
} |
||
// Returns true if any key in the 'keys' |
// Returns true if any key in the 'keys' sequence is a key of an existing Map |
||
// or false otherwise. |
// or false otherwise. |
||
static containsAny(map, keys) { |
static containsAny(map, keys) { |
||
Check.map("map", map) |
Check.map("map", map) |
||
Check. |
Check.seq("keys", keys) |
||
for (key in keys) { |
for (key in keys) { |
||
if (map[key]) return true |
if (map[key]) return true |
||
Line 68: | Line 97: | ||
} |
} |
||
// Returns true if no key in the 'keys' |
// Returns true if no key in the 'keys' sequence is a key of an existing Map |
||
// or false otherwise. |
// or false otherwise. |
||
static containsNone(map, keys) { !containsAny(map, keys) } |
static containsNone(map, keys) { !containsAny(map, keys) } |
||
// Removes all keys in the 'keys' |
// Removes all keys in the 'keys' sequence from an existing Map |
||
// and returns a list of the associated values removed. |
// and returns a list of the associated values removed. |
||
static removeAll(map, keys) { |
static removeAll(map, keys) { |
||
Check.map("map", map) |
Check.map("map", map) |
||
if (map.isEmpty) return [] |
if (map.isEmpty) return [] |
||
Check. |
Check.seq("keys", keys) |
||
var removals = [] |
var removals = [] |
||
for (key in keys) { |
for (key in keys) { |
||
Line 89: | Line 118: | ||
static removeBy(map, fn) { |
static removeBy(map, fn) { |
||
Check.map("map", map) |
Check.map("map", map) |
||
Check.func("fn", fn, 1) |
|||
if (map.isEmpty) return [] |
if (map.isEmpty) return [] |
||
var removals = [] |
var removals = [] |
||
Line 97: | Line 127: | ||
} |
} |
||
// |
// Copies the elements of 'map' to a new Map object. |
||
static copy(map) { |
|||
Check.map("map", map) |
|||
var newMap = {} |
|||
for (key in map.keys) newMap[key] = map[key] |
|||
return newMap |
|||
} |
|||
// Copies all elements from map1 and then map2 to a new Map object. |
|||
// Keys in map1 which are also present in map2 have their values replaced |
|||
// if 'replace' is true but not otherwise. |
|||
// Returns the new Map. |
|||
static union(map1, map2, replace) { |
|||
Check.map("map1", map1) |
|||
Check.map("map2", map2) |
|||
Check.bool("replace", replace) |
|||
var newMap = {} |
|||
for (key in map1.keys) newMap[key] = map1[key] |
|||
for (key in map2.keys) { |
|||
if (!replace && map1.containsKey(key)) continue |
|||
newMap[key] = map2[key] |
|||
} |
|||
return newMap |
|||
} |
|||
// Copies all elements for which map1 and map2 have keys in common to a new Map object. |
|||
// Keys in map1 have their values replaced if 'replace' is true but not otherwise. |
|||
// Returns the new Map. |
|||
static intersect(map1, map2, replace) { |
|||
Check.map("map1", map1) |
|||
Check.map("map2", map2) |
|||
Check.bool("replace", replace) |
|||
var newMap = {} |
|||
for (key in map1.keys) { |
|||
if (!map2.containsKey(key)) continue |
|||
newMap[key] = replace ? map2[key] : map1[key] |
|||
} |
|||
return newMap |
|||
} |
|||
// Copies all elements of map1 which do not have keys in common with map2 to a new Map object. |
|||
static except(map1, map2) { |
|||
Check.map("map1", map1) |
|||
Check.map("map2", map2) |
|||
var newMap = {} |
|||
for (key in map1.keys) { |
|||
if (!map2.containsKey(key)) newMap[key] = map1[key] |
|||
} |
|||
return newMap |
|||
} |
|||
// Returns whether or not map1 is a submap of map2. |
|||
static isSubmap(map1, map2) { |
|||
Check.map("map1", map1) |
|||
Check.map("map2", map2) |
|||
if (map1.count > map2.count) return false |
|||
for (key in map1.keys) { |
|||
if (!map2.containsKey(key)) return false |
|||
} |
|||
return true |
|||
} |
|||
// Returns whether or not map1 is a proper submap of map2. |
|||
static isProperSubmap(map1, map2) { |
|||
Check.map("map1", map1) |
|||
Check.map("map2", map2) |
|||
if (map1.count >= map2.count) return false |
|||
for (key in map1.keys) { |
|||
if (!map2.containsKey(key)) return false |
|||
} |
|||
return true |
|||
} |
|||
// Returns whether or not map1 is a supermap of map2. |
|||
// A specialized version of 'containsAll'. |
|||
static isSupermap(map1, map2) { |
|||
Check.map("map1", map1) |
|||
Check.map("map2", map2) |
|||
if (map1.count <= map2.count) return false |
|||
for (key in map2.keys) { |
|||
if (!map1.containsKey(key)) return false |
|||
} |
|||
return true |
|||
} |
|||
// Returns whether two maps, map1 and map2, are the same length |
|||
// and contain 'equal' elements, keys and values, using the '==' operator. |
|||
static areEqual(map1, map2) { |
|||
Check.map("map1", map1) |
|||
Check.map("map2", map2) |
|||
if (map1.count != map2.count) return false |
|||
for (key in map1.keys) { |
|||
if (!map2.containsKey(key) || map1[key] != map2[key]) return false |
|||
} |
|||
return true |
|||
} |
|||
// Returns whether two maps, map1 and map2, are the same length |
|||
// and contain the same keys but not necessarily the same corresponding values. |
|||
static sameKeys(map1, map2) { |
|||
Check.map("map1", map1) |
|||
Check.map("map2", map2) |
|||
if (map1.count != map2.count) return false |
|||
for (key in map1.keys) { |
|||
if (!map2.containsKey(key)) return false |
|||
} |
|||
return true |
|||
} |
|||
// Sorts copies of the MapEntries of 'map' into key order using the default comparer |
|||
// function: {|a, b| a < b } and returns a sequence (not list) of them. |
|||
// Doesn't affect 'map' itself but enables it to be iterated in sorted order. |
|||
static sort(map) { |
|||
Check.map("map", map) |
|||
return map.keys.toList.sort().map { |k| MapEntry.new(k, map[k]) } |
|||
} |
|||
// Sorts copies of the MapEntries of 'map' into key order using a |
|||
// comparison function 'comparer' and returns a sequence (not list) of them. |
|||
// Doesn't affect 'map' itself but enables it to be iterated in sorted order. |
|||
static sort(map, comparer) { |
|||
Check.map("map", map) |
|||
return map.keys.toList.sort(comparer).map { |k| MapEntry.new(k, map[k]) } |
|||
} |
|||
} |
|||
/* MultiSet treats a Map as if it were a Bag.*/ |
|||
class MultiSet { |
|||
// If 'key' exists in 'map' increases its value by the positive integer 'inc'. |
|||
// Otherwise creates a new entry with that key and a value of 1. |
// Otherwise creates a new entry with that key and a value of 1. |
||
// Map values must be numeric. Returns 'map' after the change. |
// Map values must be numeric. Returns 'map' after the change. |
||
static |
static add(map, key, inc) { |
||
Check.map("map", map) |
Check.map("map", map) |
||
Check. |
Check.posInt("inc", inc) |
||
if (map.containsKey(key)) { |
if (map.containsKey(key)) { |
||
map[key] = map[key] + inc |
map[key] = map[key] + inc |
||
Line 111: | Line 269: | ||
} |
} |
||
// If 'key' exists in 'map' decreases its value by 'dec'. |
// If 'key' exists in 'map' decreases its value by the positive integer 'dec'. |
||
// If the resulting value is <= 0, the entry is removed from the map. |
// If the resulting value is <= 0, the entry is removed from the map. |
||
// Map values must be numeric. Returns 'map' after the change. |
// Map values must be numeric. Returns 'map' after the change. |
||
static |
static sub(map, key, dec) { |
||
Check.map("map", map) |
Check.map("map", map) |
||
Check. |
Check.posInt("dec", dec) |
||
if (map.containsKey(key)) { |
if (map.containsKey(key)) { |
||
if (map[key] <= dec) { |
if (map[key] <= dec) { |
||
Line 128: | Line 286: | ||
// Convenience versions of the above methods where inc/dec is always 1. |
// Convenience versions of the above methods where inc/dec is always 1. |
||
static |
static add(map, key) { add(map, key, 1) } |
||
static |
static sub(map, key) { sub(map, key, 1) } |
||
// Returns the total number of members (as opposed to elements) in 'map'. |
|||
// Sorts copies of the MapEntries of 'map' into key order using the default comparer |
|||
static count(map) { |
|||
// function: {|a, b| a < b } and returns a sequence (not list) of them. |
|||
// Doesn't affect 'map' itself but enables it to be iterated in sorted order. |
|||
static sort(map) { |
|||
Check.map("map", map) |
Check.map("map", map) |
||
var total = 0 |
|||
return map.keys.toList.sort().map { |k| MapEntry.new(k, map[k]) } |
|||
for (key in map.keys) total = total + map[key] |
|||
return total |
|||
} |
} |
||
// |
// Returns whether or not all values of 'map' are equal to 1 |
||
static allDistinct(map) { |
|||
// comparison function 'comparer' and returns a sequence (not list) of them. |
|||
// Doesn't affect 'map' itself but enables it to be iterated in sorted order. |
|||
static sort(map, comparer) { |
|||
Check.map("map", map) |
Check.map("map", map) |
||
return map. |
return map.values.all { |v| v == 1 } |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
Latest revision as of 12:32, 3 November 2023
Source code
/* Module "maputil.wren" */
import "./check" for Check
/* MapUtil supplements the Map class with some other operations on maps. */
class MapUtil {
// Creates a new Map from lists of keys and values
// which must be of the same length.
static create(keys, values) {
Check.list("keys", keys)
var count = keys.count
Check.list("values", values, count, count)
var m = {}
for (i in 0...count) m[keys[i]] = values[i]
return m
}
// Creates a new Map from a sequence of keys and assigns
// the same value to all of them.
static createSame(keys, value) {
Check.seq("keys", keys)
var m = {}
for (key in keys) m[key] = value
return m
}
// Adds entries to an existing Map from lists of keys and values
// which must be of the same length.
// Keys which are already present in the Map have their values replaced
// if 'replace' is true but not otherwise.
// Returns the Map after the additions.
static addAll(map, keys, values, replace) {
Check.map("map", map)
Check.list("keys", keys)
var count = keys.count
Check.list("values", values, count, count)
Check.bool("replace", replace)
for (i in 0...count) {
if (!replace && map.containsKey(key[i])) continue
map[keys[i]] = values[i]
}
return map
}
// Adds entries to an existing Map from a sequence of keys and assigns
// the same value to all of them.
// Keys which are already present in the Map have their values replaced
// if 'replace' is true but not otherwise.
// Returns the Map after the additions.
static addAllSame(map, keys, value, replace) {
Check.map("map", map)
Check.seq("keys", keys)
Check.bool("replace", replace)
for (key in keys) {
if (!replace && map.containsKey(key)) continue
map[key] = value
}
return map
}
// Merges all the elements of map2 into map1.
// Keys which are already present in map1 have their values replaced
// if 'replace' is true but not otherwise.
// Returns map1 after the additions.
// A specialized version of 'addAll'.
static merge(map1, map2, replace) {
Check.map("map1", map)
Check.map("map2", map)
for (key in map2.keys) {
if (!replace && map1.containsKey(key)) continue
map1[key] = map2[key]
}
return map
}
// Returns true if all keys in the 'keys' sequence are keys of an existing Map
// or false otherwise.
static containsAll(map, keys) {
Check.map("map", map)
Check.seq("keys", keys)
for (key in keys) {
if (!map[key]) return false
}
return true
}
// Returns true if any key in the 'keys' sequence is a key of an existing Map
// or false otherwise.
static containsAny(map, keys) {
Check.map("map", map)
Check.seq("keys", keys)
for (key in keys) {
if (map[key]) return true
}
return false
}
// Returns true if no key in the 'keys' sequence is a key of an existing Map
// or false otherwise.
static containsNone(map, keys) { !containsAny(map, keys) }
// Removes all keys in the 'keys' sequence from an existing Map
// and returns a list of the associated values removed.
static removeAll(map, keys) {
Check.map("map", map)
if (map.isEmpty) return []
Check.seq("keys", keys)
var removals = []
for (key in keys) {
if (map.containsKey(key)) removals.add(map.remove(key))
}
return removals
}
// Removes all entries from 'map' whose key satisfies the predicate
// function 'fn' and returns a list of the associated values removed.
static removeBy(map, fn) {
Check.map("map", map)
Check.func("fn", fn, 1)
if (map.isEmpty) return []
var removals = []
for (key in map.keys) {
if (fn.call(key)) removals.add(map.remove(key))
}
return removals
}
// Copies the elements of 'map' to a new Map object.
static copy(map) {
Check.map("map", map)
var newMap = {}
for (key in map.keys) newMap[key] = map[key]
return newMap
}
// Copies all elements from map1 and then map2 to a new Map object.
// Keys in map1 which are also present in map2 have their values replaced
// if 'replace' is true but not otherwise.
// Returns the new Map.
static union(map1, map2, replace) {
Check.map("map1", map1)
Check.map("map2", map2)
Check.bool("replace", replace)
var newMap = {}
for (key in map1.keys) newMap[key] = map1[key]
for (key in map2.keys) {
if (!replace && map1.containsKey(key)) continue
newMap[key] = map2[key]
}
return newMap
}
// Copies all elements for which map1 and map2 have keys in common to a new Map object.
// Keys in map1 have their values replaced if 'replace' is true but not otherwise.
// Returns the new Map.
static intersect(map1, map2, replace) {
Check.map("map1", map1)
Check.map("map2", map2)
Check.bool("replace", replace)
var newMap = {}
for (key in map1.keys) {
if (!map2.containsKey(key)) continue
newMap[key] = replace ? map2[key] : map1[key]
}
return newMap
}
// Copies all elements of map1 which do not have keys in common with map2 to a new Map object.
static except(map1, map2) {
Check.map("map1", map1)
Check.map("map2", map2)
var newMap = {}
for (key in map1.keys) {
if (!map2.containsKey(key)) newMap[key] = map1[key]
}
return newMap
}
// Returns whether or not map1 is a submap of map2.
static isSubmap(map1, map2) {
Check.map("map1", map1)
Check.map("map2", map2)
if (map1.count > map2.count) return false
for (key in map1.keys) {
if (!map2.containsKey(key)) return false
}
return true
}
// Returns whether or not map1 is a proper submap of map2.
static isProperSubmap(map1, map2) {
Check.map("map1", map1)
Check.map("map2", map2)
if (map1.count >= map2.count) return false
for (key in map1.keys) {
if (!map2.containsKey(key)) return false
}
return true
}
// Returns whether or not map1 is a supermap of map2.
// A specialized version of 'containsAll'.
static isSupermap(map1, map2) {
Check.map("map1", map1)
Check.map("map2", map2)
if (map1.count <= map2.count) return false
for (key in map2.keys) {
if (!map1.containsKey(key)) return false
}
return true
}
// Returns whether two maps, map1 and map2, are the same length
// and contain 'equal' elements, keys and values, using the '==' operator.
static areEqual(map1, map2) {
Check.map("map1", map1)
Check.map("map2", map2)
if (map1.count != map2.count) return false
for (key in map1.keys) {
if (!map2.containsKey(key) || map1[key] != map2[key]) return false
}
return true
}
// Returns whether two maps, map1 and map2, are the same length
// and contain the same keys but not necessarily the same corresponding values.
static sameKeys(map1, map2) {
Check.map("map1", map1)
Check.map("map2", map2)
if (map1.count != map2.count) return false
for (key in map1.keys) {
if (!map2.containsKey(key)) return false
}
return true
}
// Sorts copies of the MapEntries of 'map' into key order using the default comparer
// function: {|a, b| a < b } and returns a sequence (not list) of them.
// Doesn't affect 'map' itself but enables it to be iterated in sorted order.
static sort(map) {
Check.map("map", map)
return map.keys.toList.sort().map { |k| MapEntry.new(k, map[k]) }
}
// Sorts copies of the MapEntries of 'map' into key order using a
// comparison function 'comparer' and returns a sequence (not list) of them.
// Doesn't affect 'map' itself but enables it to be iterated in sorted order.
static sort(map, comparer) {
Check.map("map", map)
return map.keys.toList.sort(comparer).map { |k| MapEntry.new(k, map[k]) }
}
}
/* MultiSet treats a Map as if it were a Bag.*/
class MultiSet {
// If 'key' exists in 'map' increases its value by the positive integer 'inc'.
// Otherwise creates a new entry with that key and a value of 1.
// Map values must be numeric. Returns 'map' after the change.
static add(map, key, inc) {
Check.map("map", map)
Check.posInt("inc", inc)
if (map.containsKey(key)) {
map[key] = map[key] + inc
} else {
map[key] = 1
}
return map
}
// If 'key' exists in 'map' decreases its value by the positive integer 'dec'.
// If the resulting value is <= 0, the entry is removed from the map.
// Map values must be numeric. Returns 'map' after the change.
static sub(map, key, dec) {
Check.map("map", map)
Check.posInt("dec", dec)
if (map.containsKey(key)) {
if (map[key] <= dec) {
map.remove(key)
} else {
map[key] = map[key] - dec
}
}
return map
}
// Convenience versions of the above methods where inc/dec is always 1.
static add(map, key) { add(map, key, 1) }
static sub(map, key) { sub(map, key, 1) }
// Returns the total number of members (as opposed to elements) in 'map'.
static count(map) {
Check.map("map", map)
var total = 0
for (key in map.keys) total = total + map[key]
return total
}
// Returns whether or not all values of 'map' are equal to 1
static allDistinct(map) {
Check.map("map", map)
return map.values.all { |v| v == 1 }
}
}