如何通过标题的第一个字母来创build字典,但忽略“the”或“a / an”等文章

我想按我的表格视图中媒体项目的标题对数据进行sorting,但是我想按照第一个“实际”字母sorting,而不用“the”或“an”

  • 一首民谣
  • 红胡子海盗的民谣
  • 黑胡子海盗的民谣
  • 钢球

我尝试了下面的解决scheme:

extension String { func firstLetter() -> Character{ var tmp = self.lowercased() if tmp.hasPrefix("the "){ tmp = String(tmp.characters.dropFirst(4)) }else if tmp.hasPrefix("a "){ tmp = String(tmp.characters.dropFirst(2)) }else if tmp.hasPrefix("an "){ tmp = String(tmp.characters.dropFirst(3)) } let hmm = "aąbcćdeęfghijklmnoópqrsśtuvwxyzżź0123456789" let letters = Array(hmm.characters) for index in characters.indices{ if letters.contains(tmp[index]){ return tmp[index] } } return "_" } func firstSpecial() -> Bool { let characterset = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") if prefix(1).rangeOfCharacter(from: characterset.inverted) != nil { return true }else{ return false } } func firstNumber() -> Bool { if lowercased().hasPrefix("the "){ return Int(dropFirst(4).prefix(1)) != nil }else if lowercased().hasPrefix("a "){ return Int(dropFirst(2).prefix(1)) != nil }else if lowercased().hasPrefix("an "){ return Int(dropFirst(3).prefix(1)) != nil }else{ return Int(prefix(1)) != nil } } } songs = [MPMediaItem]() result = [String: [MPMediaItem]]() indexes = [String]() func setup(){ var numbers = false var special = false songs = musicQuery.shared.songs for song in songs { var key = "" if song.title!.firstNumber() { print(song.title) key = "#" if result[key] != nil { result[key]?.append(song) }else{ result[key] = [] result[key]?.append(song) numbers = true } }else if !(song.title?.firstSpecial())! { key = String(describing: song.title?.firstLetter()).uppercased() if result[key] != nil { result[key]?.append(song) }else{ result.updateValue([song], forKey: key) indexes.append(key) } }else{ print(song.title) key = "?" if result[key] != nil { result[key]?.append(song) }else{ result[key] = [] result[key]?.append(song) special = true } } } indexes = indexes.sorted { $0.compare($1) == ComparisonResult.orderedAscending } if numbers { indexes.append("#") } if special { indexes.append("?") } } 

但是,这是很不理想,需要很长时间才能完成和省略一些条目

简化的解决scheme,只需更换那些在sorting时不想包含的文章。

  let unsortedList = ["Ballad of El Red Beard Pirate","A Ballad","Ballad of An Red Beard Pirate","The Ballad of Black Beard Pirate","Balls of steel"]; func removeLeadingArticle(string: String) -> String { let articles = ["The ", "A ", "of "," An"]; var changedStr = string; for (_,article) in articles.enumerated() { changedStr = changedStr.replacingOccurrences(of: article, with: ""); } print("changed string \(changedStr)"); return changedStr; } let sortedList = unsortedList.sorted { (firstStr, secondStr) -> Bool in let title1 = removeLeadingArticle(string: firstStr); let title2 = removeLeadingArticle(string: secondStr); return title1.localizedCaseInsensitiveCompare(title2) == ComparisonResult.orderedAscending } print("sorted list \(sortedList)"); 

输出————

 changed string Ballad changed string Ballad El Red Beard Pirate changed string Ballad Red Beard Pirate changed string Ballad El Red Beard Pirate changed string Ballad Black Beard Pirate changed string Ballad Red Beard Pirate changed string Ballad Black Beard Pirate changed string Ballad El Red Beard Pirate changed string Ballad Black Beard Pirate changed string Ballad changed string Balls steel changed string Ballad Red Beard Pirate sorted list ["A Ballad", "The Ballad of Black Beard Pirate", "Ballad of El Red Beard Pirate", "Ballad of An Red Beard Pirate", "Balls of steel"] 

获得词典与领导人物作为关键忽略“A”,“An”,“The”。

  let unsortedList = ["A Ballad","Ballad of An Red Beard Pirate","The Ballad of Black Beard Pirate","All Balls of steel","Red Riding Hood","The Earth"]; let articles = ["The","A","An"]; var dictionary:Dictionary = Dictionary<String,String>(); for objStr in unsortedList { let article = objStr.components(separatedBy: " ").first!; print("article: \(article)"); if articles.contains(article) { if objStr.components(separatedBy: " ").count > 1 { let secondStr = objStr.components(separatedBy: " ")[1]; dictionary["\(secondStr.first!)"] = objStr; } }else { dictionary["\(article.first!)"] = objStr; } } print("dictionary:- \(dictionary)"); 

产量——–

文章:文章:文章:文章:全文:红色文章:

 dictionary:- ["R": "Red Riding Hood", "B": "The Ballad of Black Beard Pirate", "A": "All Balls of steel", "E": "The Earth"] 

为了做到这一点,你可以尝试使用这个实用工具,删除作为parameter passing的任何前缀。 它使用第一个匹配replace: https : //stackoverflow.com/a/40863622/8236481 e

 extension String { func removingPrefixes(_ prefixes: [String]) -> String { var resultString = self prefixes.map { if resultString.hasPrefix($0) { resultString = resultString.dropFirst($0.count).description } } return resultString } } 

使用这个函数,你现在可以使用这个函数对string数组进行sorting:

 extension Array where Element == String { func sorted(ignoring: [String]) -> [String] { let filteredData = self.map { $0.lowercased().removingPrefixes(ignoring) } let sortedData = filteredData.enumerated().sorted { $0.element < $1.element } return sortedData.map { self[$0.offset] } } } 
  1. 从input数据中删除任何不需要的文章。
  2. sorting该数组
  3. 使用sorting的数组索引返回原始数组

希望它帮助你!

您可以使用数组中的内置sorting(变异)或sorting(复制)函数按照您希望的顺序进行sorting。 在这种情况下,你需要做的是在比较两个string之前去掉你不想要的任何前缀。 这不是最有效的解决scheme,因为你可以cachingreplace计算(即添加一个字段到预先计算的sortingstring的模型或预先计算sortingstring的字典),但它确实有效。

 import PlaygroundSupport import UIKit func strippingArticles(from: String) -> String { let articles = ["The ", "A "] var target = from for article in articles { if target.hasPrefix(article) { target = String(target.dropFirst(article.count)) } } return target } let unsortedTitle = ["Title", "The sample", "A word"] let sortedTitles = unsortedTitle.sorted { (lhs: String, rhs: String) -> Bool in let left = strippingArticles(from: lhs) let right = strippingArticles(from: rhs) return left.compare(right) == .orderedAscending } print(sortedTitles) 

不要试图弄清楚这些文章是什么; 使用iOS内置的智能。 使用NSLinguisticTagger将文本标记为单词,从而将其分解为词类 。 现在你知道在你sorting时要忽略什么原始文本。

之后,这只是一个共同的问题。 这是堆栈溢出已被处理了很多次。