2016-04-25 50 views
1

我有一个String阵列:斯威夫特函数式编程

let animals = ["Cat", "Chicken", "Fish", "Dog", "Mouse", "Pig", "Monkey"] 

我想要得到的结果是这样的:

[(C, ["Cat", "Chicken"]), 
(D, ["Dog"]), 
(F, ["Fish"]), 
(M, ["Mouse", "Monkey"]), 
(P, ["Pig"])] 

我曾尝试:

let animals = ["Cat", "Chicken", "Fish", "Dog", "Mouse", "Pig", "Monkey"] 
typealias Entry = (Character, [String]) 

func buildIndex(words: [String]) -> [Entry] { 
    let distinctLetters = Array(Set(words.map { Character($0.substringToIndex($0.startIndex.advancedBy(1))) })).sort() 
    return distinctLetters.map({ (letter) -> Entry in 
     return (letter, words.filter({ (word) -> Bool in 
      Character(word.substringToIndex(word.startIndex.advancedBy(1))) == letter 
     })) 
    }) 
} 
print(buildIndex(animals)) 

//[("C", ["Cat", "Chicken"]), ("D", ["Dog"]), ("F", ["Fish"]), ("M", ["Mouse", "Monkey"]), ("P", ["Pig"])] 

现在我想与$语法一起使用。

我曾尝试:

func buildIndex(words: [String]) -> [Entry] { 
    let distinctLetters = Array(Set(words.map { Character($0.substringToIndex($0.startIndex.advancedBy(1))) })).sort() 
    return distinctLetters.map{ ($0, words.filter { 
     Character($0.substringToIndex($0.startIndex.advancedBy(1))) == $0 // I want to get $0 from the map, not from the filter 
    })} 
} 

enter image description here

但它说:

重载 '==' 这些部分匹配参数 列表存在:(人品,人品) ,(String,String) Character($ 0.substringToIndex($ 0.startIndex.advancedBy(1)))== $ 0

我也曾尝试:

func buildIndex(words: [String]) -> [Entry] { 
    let distinctLetters = Array(Set(words.map { Character($0.substringToIndex($0.startIndex.advancedBy(1))) })).sort() 
    return distinctLetters.map { ($0, words.filter { distinctLetters.contains(Character($0.substringToIndex($0.startIndex.advancedBy(1)))) })} 
} 

,但它不能很好地工作。它打印:

[("C", ["Cat", "Chicken", "Fish", "Dog", "Mouse", "Pig", "Monkey"]), ("D", ["Cat", "Chicken", "Fish", "Dog", "Mouse", "Pig", "Monkey"]), ("F", ["Cat", "Chicken", "Fish", "Dog", "Mouse", "Pig", "Monkey"]), ("M", ["Cat", "Chicken", "Fish", "Dog", "Mouse", "Pig", "Monkey"]), ("P", ["Cat", "Chicken", "Fish", "Dog", "Mouse", "Pig", "Monkey"])] 

那么如何实现这与$ systax。

任何帮助,将不胜感激。谢谢。

+2

你在不同'$ 0'之间有冲突。只要保持你的参数命名,它使它们更具可读性。通过用'$ 0'代替名字,你只用你的代码做了一件事 - 你正在降低可读性。你没有使代码或多或少的功能。 – Sulthan

+0

'buildIndex'的第二次尝试看起来像有一些复制/粘贴错误。 –

+0

因为编译器不知道'map'中的'$ 0'。当我输入'$ 0'时,编译器提示2 $ 0,一个是'String',另一个是'Character'。当然,我选择了“Character”,但它没有奏效。 – Khuong

回答

1

考虑一下:

let animals = ["Cat", "Chicken", "Fish", "Dog", "Mouse", "Pig", "Monkey"] 

let catalog = Array(Set(animals.map({(ch) -> Character in ch.characters.first! }))) 
    .sort() 
    .map({ (ch) -> (Character, [String]) in 
     (ch, animals.filter { (name) -> Bool in name.hasPrefix(String(ch)) }) 
    }) 

print(catalog) 
//[("C", ["Cat", "Chicken"]), ("D", ["Dog"]), ("F", ["Fish"]), ("M", ["Mouse", "Monkey"]), ("P", ["Pig"])] 
+0

切换到字符是一个好主意,但问题是“我可以使用点符号来解决这个问题吗?” –

+0

但你的好答案+1投票。 – Khuong

1

什么做这种方式:

func buildIndex2(words: [String]) -> [Entry] { 
    var res = [Character:[String]]() 
    words.map({ res[$0[0]] = (res[$0[0]] ?? []) + [$0] }) 
    return res.sort{ $0.0 < $1.0 } 
} 

甚至更​​多$三通(在我看来,可读性变差,虽然):

func buildIndex3(words: [String]) -> [Entry] { 
    return animals.reduce([Character:[String]]()) { 
     var res = $0 
     res[$1[0]] = ($0[$1[0]] ?? []) + [$1] 
     return res 
    }.sort{ $0.0 < $1.0 } 
} 

字符串扩展:

extension String { 
    subscript (i: Int) -> Character { 
     return self[self.startIndex.advancedBy(i)] 
    } 
} 

此解决方案的优点是,您不必为每个字母在最后一个地图的每个步骤中都运行过滤器。

+0

+您的良好答案投票。 – Khuong

+0

增加了一个解决方案来摆脱范围变量'res',但它在我看来不太可读... – Michal

+0

是的。这里有很多'$ 0',我之所以问这个问题是因为上面的图片。 – Khuong