Danny Danny - 1 year ago 72
iOS Question

How to use variable with the same name as String Swift

I am trying to optimize my code. I want to do the following: if I have an element in the dictionary

that is in
array I want to write this element directly to the
variable, same with
and etc. Here my code example. I've created
array that contains linked variables
and etc.
Also I am trying to iterate through the loop and to set values to
and etc. using

let dict = ["type": "1", "word": "abc"] // this is example
let firstNames = ["1", "2"]
let secondNames = ["3", "4"]
var first = String()
var second = String()
let names = [firstNames: first, secondNames: second]
for el in dict {
for var (key, val) in names {
if (key as! [String]).contains(el["type"]!) {
if ((val as! String) != "") {
val = (val as! String) + ", " + el["word"]!
else {
val = el["word"]!

This code doesn't have any runtime errors. But unfortunately when I am trying to set
in the loop nothing is happening. What I am doing wrong or may be there is a more elegant solution?

Thanks for any help.

Answer Source

Swift is a compiled, mostly static language, and the optimizer is free to have removed these temporary variables entirely if they aren't needed. The names of local variables aren't available at runtime. This approach won't work. It could work if you used a dictionary to hold "first" and "second" as string keys (which is where Paulw11 is pointing you), but this is the wrong approach in Swift.

Let's start with dict. This is not a proper use of a Dictionary. This is not a arbitrary mapping of strings to strings. It is a mapping of specific field identifiers to values. That's the definition of a struct.

It is possible that "type" really is "an arbitrary integer," but I strongly suspect that it is actually "a value from a constrained list of values." That's a enum.

If we put those together, dict is really Element:

enum ElementType {
    case one
    case two
    case three
    case four

struct Element {
    let type: ElementType
    let word: String

And your name selectors are arbitrary lists of ElementTypes:

let firstNameTypes = [ElementType.one, .two]
let secondNameTypes = [ElementType.three, .four]

Then, rather than just one dict, we can imagine lists of elements (which I assume you actually have outside this loop).

let elements = [
    Element(type: .one, word: "abc"),
    Element(type: .two, word: "bcd"),
    Element(type: .three, word: "efg"),
    Element(type: .four, word: "fgh"),

And now our loop is trivial and clearly says what it means.

let firstNames = elements.filter { firstNameTypes.contains($0.type) }
let secondNames = elements.filter { secondNameTypes.contains($0.type) }

And to get our final string is also trivial:

let firstString = firstNames.map { $0.word }.joined(separator: ",")
let secondString = secondNames.map { $0.word }.joined(separator: ",")

While this code is very clear, it does iterate over the elements twice and over the "NameTypes" lists once for each element. In the vast majority of cases, that's fine. It's what computers do, But if you have many thousands of elements (and especially if the name filtering lists were long), it could be expensive and we could write a function that returned a dictionary of result strings (by rewriting filter by hand). If that's your problem, I can write that up (if you'll explain the underlying problem more clearly), but in most cases for modest sized lists, this is the best approach.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download