简体   繁体   English

使用for-in循环快速替换数组中的字符串

[英]Swift replace string in array using for-in loop

As a learning exercise , I am trying to use a for-in loop to replace a String in an Array (with a dictionary value) if the String is an existing key in a Dictionary . 作为学习练习 ,如果StringDictionary的现有键,则尝试使用for-in循环替换ArrayString (具有字典值)。 I already know how to do this using .stringByReplacingOccurrencesOfString , but I'd like to learn what I'm doing wrong here, and how to accomplish this with a for-in loop. 我已经知道如何使用.stringByReplacingOccurrencesOfString来执行此操作,但是我想了解我在这里做错了什么,以及如何使用for-in循环来完成此操作。

let sillyMonkeyString = "A monkey stole my iPhone"
let dictionary = ["monkey": "🐒", "iPhone":"📱"]
var toArray = sillyMonkeyString.componentsSeparatedByString(" ")
// desired result is "A 🐒 stole my 📱"

Here is what doesn't work: 这是行不通的:

for var str in toArray {
    if let val = dictionary[str] {
        str = val                  
    }
}
let backToString = toArray.joinWithSeparator(" ")

What does work: 什么有效:

var newArray = [String]()
for var str in toArray {
    if let val = dictionary[str] {
        str = val
    }
    newArray.append(str)
}
let backToString = newArray.joinWithSeparator(" ")

This works because I'm creating a new array and appending to the new array. 这行得通,因为我正在创建一个新数组并将其追加到新数组中。 However, my original Array is mutable, so why is the first solution not correctly assigning str to val in the original Array inside the for-in loop? 但是,我的原始Array 可变的,那么为什么第一个解决方案没有在for-in循环内的原始Array正确地将str分配给val The only other related question I found here had a great one-line answer that did not explain whether or not I can accomplish this using a for-in loop. 我在这里找到的唯一其他相关问题有一个很棒的单行答案,该答案没有解释我是否可以使用for-in循环来完成此任务。

UPDATE: I do not recommend implementing a for-in loop for this particular use case. 更新:我不建议为此特定用例实现for-in循环。 I asked this question to learn how to do this. 我问了这个问题以学习如何做。 If a user would like to replace parts of strings with a dictionary, I highly recommend considering using one of the more efficient and Swifty solutions below (which may not be the accepted solution) 如果用户想用字典替换字符串的某些部分,我强烈建议考虑使用以下更有效和快速的解决方案之一(可能不是公认的解决方案)

'pure' Swift (no import Foundation) and 'functional' way leads to “纯” Swift(无需导入基金会)和“功能”方式导致

let sillyMonkeyString = "A monkey stole my iPhone"
let dictionary = ["monkey": "🐒", "iPhone":"📱"]

let arr = sillyMonkeyString.characters.split(" ").map(String.init)
let result = arr.map { dictionary[$0] ?? $0 }.joinWithSeparator(" ")

print(result)
// A 🐒 stole my 📱

if for in loop is required, than 如果需要for循环,

var resArr:[String] = []
for txt in arr {
    resArr.append(dictionary[txt] ?? txt)
}
let result2 = resArr.joinWithSeparator(" ") // A 🐒 stole my 📱"

if you would like to have mutating solution ... 如果您想使用变异解决方案...

let sillyMonkeyString = "A monkey stole my iPhone"
let dictionary = ["monkey": "🐒", "iPhone":"📱"]

var arr = sillyMonkeyString.characters.split(" ").map(String.init)

for (idx,value) in arr.enumerate() {
    arr[idx] = dictionary[value] ?? value
}
let result3 = arr.joinWithSeparator(" ") // "A 🐒 stole my 📱"

if you don't like enumerate(), you can use indices instead 如果您不喜欢enumerate(),可以改用索引

let sillyMonkeyString = "A monkey stole my iPhone"
let dictionary = ["monkey": "🐒", "iPhone":"📱"]

var arr = sillyMonkeyString.characters.split(" ").map(String.init)

for i in arr.indices {
    arr[i] = dictionary[arr[i]] ?? arr[i]
}
let result4 = arr.joinWithSeparator(" ") // "A 🐒 stole my 📱"

When declaring something as "var" in a for loop or "if var"(deprecated) statement, the value is copied to that variable, not the reference. 在for循环或“ if var”(不建议使用)语句中将某些内容声明为“ var”时,会将值复制到该变量,而不是引用。 So when you change "val", you're changing that local variable and not changing the object that exists in toArray 因此,当您更改“ val”时,您将更改该局部变量,而不是更改toArray中存在的对象

If you want to change it within the array, this should work (not compiled fyi): 如果要在数组中更改它,这应该起作用(不编译fyi):

for str in toArray {
    if let val = dictionary[str] {
        toArray[toArray.indexOf(str)] = val
    }
}

Alternately, you can track the index instead with 另外,您也可以使用

for i in 0 ..< toArray.count {
    if let val = dictionary[toArray[i]] {
        toArray[i] = val
    }
}

To give an comparable example to the link you sent, you could do something like this: 为了给您发送的链接提供一个可比较的示例,您可以执行以下操作:

toArray = toArray.map { dictionary[$0] ?? $0 }

If you're unfamiliar with the map function, I would suggest looking it up as it's one of the best features in swift! 如果您不熟悉地图功能,建议您查找它,因为它是swift的最佳功能之一! :) :)

str = val will only change the value in your local variable, which is valid only in the scope of the for loop. str = val将仅更改局部变量中的值,该值仅在for循环范围内有效。 The value in the array will no be changed. 数组中的值将不会更改。 What you want really is: 您真正想要的是:

for i in 0..< toArray.count {
    if let val = dictionary[toArray[i]] {
        toArray[i] = val
    }
}

This is the solution I came up with. 这是我想出的解决方案。 I'll consider using others since many have recommended that using .indexOf is very expensive. 我会考虑使用其他人,因为许多人建议使用.indexOf非常昂贵。 Rather than assigning to an ivar, I'm assigning val directly to the item at the current index in the original array. 而不是分配给ivar,而是直接将val分配给原始数组中当前索引处的项。 I'm all for learning and implementing what is least costly. 我全力以赴学习和实施成本最低的东西。 However, you got to admit this is clean and short. 但是,您必须承认这很干净而且简短。 (though not the most efficient) (尽管不是最有效的)

for var str in toArray {
    if let val = dictionary[str] {
        toArray[toArray.indexOf(str)!] = val
    }
}

How about this approach: 这种方法怎么样:

var sillyMonkeyString = "A monkey stole my iPhone"
let dictionary = ["monkey": "🐒", "iPhone":"📱"]
var toArray = sillyMonkeyString.componentsSeparatedByString(" ")

for (index, string) in toArray.enumerate()
{
  if let val = dictionary[string]
  {
    toArray[index] = val
  }
}
let finalString = toArray.joinWithSeparator(" ")

That code uses a variant of for...in that returns the objects in an array and the index as tuples. 该代码使用for ... in的变体,它返回数组中的对象并将索引作为元组返回。 Some other answers used indexOf . 其他一些答案使用indexOf indexOf is both computationally expensive, and potentially risky. indexOf在计算上既昂贵又有潜在风险。 Arrays can contain multiple copies of the same object, so the string in question could occur at multiple places. 数组可以包含同一对象的多个副本,因此所讨论的字符串可能出现在多个位置。 In this particular example, it works because we loop through the array of words front to back, replacing matching words as we go. 在此特定示例中,它之所以起作用,是因为我们从头到尾遍历单词数组,并在进行时替换匹配的单词。 So, indexOf will always find the first remaining occurrence of the string. 因此,indexOf将始终找到字符串的第一个剩余出现位置。 Nevertheless, it is still quite slow on large arrays. 但是,在大型阵列上它仍然相当慢。

You can use forEach to iterate through your dictionary key/value pairs and replace them as follow: 您可以使用forEach遍历字典键/值对,并按如下所示替换它们:

var sillyMonkeyString = "A monkey stole my iPhone"
let dictionary = ["monkey": "🐒", "iPhone":"📱"]

dictionary.forEach{ sillyMonkeyString = sillyMonkeyString.stringByReplacingOccurrencesOfString($0.0, withString: $0.1) }
print(sillyMonkeyString)  // "A 🐒 stole my 📱"

On the topic of "what was wrong" in the code that didn't work : 在无效的代码中出现“出了什么问题”的话题:

 for var str in toArray {
     if let val = dictionary[str] {
         str = val                  
     }
 }
 let backToString = toArray.joinWithSeparator(" ")

The str variable in your for loop is not a reference to the elements of your toArray but a copy of it. for循环中的str变量不是对toArray元素的引用,而是对其的副本。 So modifying str inside the loop has no effect on the array it came from. 因此,在循环内部修改str对其源数组没有影响。

As others have said, instead of 正如其他人所说,

for var str in toArray {

if must be 如果必须

for str in toArray {

But I want to show another approach, using enumerate() on dictionary 但我想展示另一种方法,在字典上使用enumerate()

var sillyMonkeyString = "A monkey stole my iPhone"
let dictionary = ["monkey": "🐒", "iPhone":"📱"]

for (_ ,v) in dictionary.enumerate() {
    sillyMonkeyString = sillyMonkeyString.stringByReplacingOccurrencesOfString(v.0, withString: v.1)
}

print(sillyMonkeyString)

prints A 🐒 stole my 📱 打印A 🐒 stole my 📱

enumerate() returns a tuple containing of the index and the tuple with the key and value. enumerate()返回一个包含索引的元组以及具有键和值的元组。

and to make tanzolone happy, though this is a rather stupid approach: 并让坦佐隆开心,尽管这是一个很愚蠢的方法:

let sillyMonkeyString = "A monkey stole my iPhone"
let dictionary = ["monkey": "🐒", "iPhone":"📱"]
var toArray = sillyMonkeyString.componentsSeparatedByString(" ")

for (i,v) in dictionary.enumerate() {
    for (j,s) in toArray.enumerate() {
        if s == v.0 {
            toArray[j] = v.1
        }
    }
}

print(toArray.joinWithSeparator(" "))

enumeration with for in 用for枚举

var sillyMonkeyString = "A monkey stole my iPhone"
let dictionary = ["monkey": "🐒", "iPhone":"📱"]

for (k,v) in dictionary{
    sillyMonkeyString = sillyMonkeyString.stringByReplacingOccurrencesOfString(k, withString: v)
}

print(sillyMonkeyString)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何对字符串 API 数组使用 for-in 循环,并使用每个 API 链接在 Xcode 中的 Swift 中解析相同的 JSON 结构 - How to use a for-in loop for an array of string APIs and using each API link to parse the same JSON structure in Swift in Xcode 在Swift中使用数组的For-In循环中Iterator元素的可变性 - Mutability of the Iterator Element in a For-In loop with an Array in Swift 我可以使用 for-in 循环更新全局数组,并在循环外使用更新后的数组吗? (迅速) - Can I update a global array using a for-in loop, and use the updated array outside of the loop ? (Swift) 如何在 swift for-in 循环中使用 array.count - how to use array.count in swift for-in loop 使用Swift的for-in循环中的一组字符串填充数组 - Populate Array with a set of Strings from a for-in loop for Swift 在for-in循环中更改数组的名称 - Changing the name of an array in a for-in loop 推送到for-in循环数组以扩展for-in循环的迭代次数 - Pushing to array of for-in loop to extend the number of iterations of that for-in loop 使用 For-In 循环检查重复项 - Checking for Duplicates Using For-In Loop 在循环中使用数组替换字符串中的字符 - Replace character in a string, using an array in a loop 在for-in循环中更改数组的大小 - Changing the size of an array inside of in for-in loop
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM