作为一个练习练习,作为一个练习练习,我正在尝试写一个等同于下划线的快照.js' _.each
:
_.each({foo: true, bar: false}, function(value, key) {...}
_.each([true, false], function(value, key) {...}
但由于枚举(集合)为字典和数组返回不同类型的结果,因此证明是困难的:
for (indexInt, (key, value)) enumerate(["foo": true]) {...}
for (key, value) enumerate([true]) {...}
如何在不明确检查Array
或Dictionary
的通用集合类的情况下处理这两种不同的返回类型?
返回类型检查将失败,因为以下两个示例应区别对待,但从enumerate()返回等效类型:
for (indexInt, (key, value)) enumerate(["foo": true]) {...}
for (indexInt, (key, value)) enumerate([("foo", true")]) {...}
此外,FWIW,$ .swift似乎对此表示不满:
https://github.com/ankurp/Dollar.swift/blob/master/Dollar/Dollar/Dollar.swift#L193-L217
编辑:格式化。还.. ..
破碎的通用实施
func each<C: Collection>(collection: C, fn: (Any, Any) -> ()) -> C {
// On next line... Error: Tuple pattern cannot match values of the non-tuple type 'C.GeneratorType.Element'
for (_, (k, v)) in enumerate(collection) {
if let innerV = collection[innerK] {
fn(innerV, k)
}
}
return collection
}
var ret = each(["foo":true, "bar":false]) { println("Key \($1), Value:\($0)") }
正在进行的词典实施
func eachDictionary<K,V>(collection: Dictionary<K, V>, fn: (V, K) -> ()) -> Dictionary<K, V> {
for (_, (k, v)) in enumerate(collection) {
fn(v, k)
}
return collection
}
var retDictionary = eachDictionary(["foo":true, "bar":false]) { println("Key \($1), Value:\($0)") }
正在运行的数组实现
func each<V>(collection: V[], fn: (V, Int) -> ()) -> V[] {
for (k, v) in enumerate(collection) {
fn(v, k)
}
return collection
}
var retArray = each([true, false]) { println("Key \($1), Value:\($0)") }
编辑2:更新了使用重载的示例。 我具体询问是否有通用的收集协议方法来实现这一点,而不需要为每种收集类型提供一次性服务?
编辑3:我尝试了以下内容(我必须在空数组中添加更多类型,以便它不会抱怨回调的参数不可打印)但是......
(K,V)
作为值传递)[(V1,V2)]
案例(K, V)
代替(Any, Any)
代码:
func each<C: Collection>(collection: C, fn: (Any, Any) -> ()) -> C {
for (k, v) in enumerate(collection) {
if let (key, value) = v as? (Any, Any) {
fn(value, key)
} else {
fn(v, k)
}
}
return collection
}
var ret = each(["foo":true, "bar":false]) { println("1: Key \($1), Value:\($0)") }
var arr : String[] = []
var retOne = each(arr) { println("2: Key \($1), Value:\($0)") }
var retTwo = each([true, false]) { println("3: Key \($1), Value:\($0)") }
答案 0 :(得分:2)
JavaScript和Swift之间最大的区别之一是你可以定义具有不同签名(重载)的相同名称的(function | method)。只需使用它。
class $ {
class func map<K:Hashable,V,R>
(dictionary:[K:V], block:(V,K)->R)->[K:R] {
var result = [K:R]()
for (k, v) in dictionary {
result[k] = block(v, k)
}
return result
}
class func map<V,R>
(array:[V], block:(V,Int)->R)->[R] {
var result = [R]()
for (k, v) in enumerate(array) {
result.append(block(v, k))
}
return result
}
class func each<K:Hashable,V,R>
(dictionary:[K:V], block:(V,K)->R) {
for (k, v) in dictionary { block(v, k) }
}
class func each<V,R>
(array:[V], block:(V,Int)->R) {
for (k, v) in enumerate(array) { block(v, k) }
}
}
println($.map(["zero":0, "one":1], { n,_ in n+1 }))
println($.map([0,1], { n,_ in n+1 }))
$.each(["zero":0, "one":1]) { println("\($1) => \($0)") }
$.each([0, 1]) { println("\($1) => \($0)") }
答案 1 :(得分:1)
枚举不是你的问题。字典是。您尝试做的事情不太可行,因为这不是基于Collection的含义。 Dictionary中的键与传递给Array的整数无关。词典的索引是DictionaryIndex
,而不是KeyType
。
首先,让我们考虑如何将其写为通用函数(不能做你想要的,但正是你可以在Collection上做的):
func each<C:Collection>(collection: C, fn:(C.GeneratorType.Element, C.IndexType) -> ()) -> C {
for index in indices(collection) {
fn(collection[index], index)
}
return collection
}
它遍历集合并将其值和索引传递给接受它们的某个函数。对于数组,此函数将具有签名:
(T, Int) -> ()
对于词典,此函数将具有签名
(ValueType, DictionaryIndex<KeyType, ValueType>) -> ()
您对enumerate
的使用只会掩盖这一根本问题。 Collection是一个Sequence,它通过下标传递索引时返回一个值。这就是全部。序列是可以通过生成器生成值的东西。这就是全部。在这两者之间,他们对字典键一无所知。从通用的角度来看,字典只是一系列键/值元组。
现在,你喜欢的真实情况是,Dictionary的索引是它的键。但事实并非如此。讨论Dictionary的密钥没有通用的方法,因为它们不是Collection协议的一部分(而且Array和Dictionary共享没有其他常见的协议可以挂起来)。
那么为什么,你可能会问,你能说dict[key]
并获得价值吗?这与Collection无关。这是Dictionary中的一个额外的下标方法(评论我的):
// This is the Collection subscript
subscript (i: DictionaryIndex<KeyType, ValueType>) -> (KeyType, ValueType) { get }
// This is a subscript unrelated to Collection
subscript (key: KeyType) -> ValueType?
由于Collection对Dictionaries的键一无所知,因此几乎肯定不可能解决这个问题。
我怀疑Dictionary的键不是索引的原因与dict[key]
返回Optional的事实有关,而array[num]
(通常是Collection的下标)返回实际值。