1

I am trying to optimize my code. I want to do the following: if I have an element in the dictionary dict that is in firstNames array I want to write this element directly to the first variable, same with second and etc. Here my code example. I've created names array that contains linked variables firstNames <-> first, secondNames <-> second and etc. Also I am trying to iterate through the loop and to set values to first, second and etc. using val

    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 val in the loop nothing is happening. What I am doing wrong or may be there is a more elegant solution?

Thanks for any help.

4
  • 2
    I am not fully following exactly what you want to do. Could you add an example of what dict looks like? Right now your names variable is a dictionary with name as array and value is string ([[String],String]). Commented Aug 7, 2016 at 12:30
  • @PaulPeelen added, my question is more about detecting if I have variable 1abc then write to 1abcd, if I have 2abc then write to 2abcd, if I have 3abc then write to 3abcd... I mean that how to get name of variable 2 from the same name (partially the same) of variable 1 Commented Aug 7, 2016 at 12:41
  • 1
    You can't write to a variable using a variable name that is another variable. Use a dictionary, with the key as your "variable name" Commented Aug 7, 2016 at 12:53
  • @Paulw11 If I will have a dictionary with key as "variable name" and value as variable (example ` let secondDict = ["variable": variable]), how will I write to the variable then? If I use secondDict["variable"] = "smth"` I will just update a dictionary, but I need to update variable. Commented Aug 7, 2016 at 13:07

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Well written, better than the answer I was about to write. You can, however, cast the name selectors like let firstNameTypes: [ElementType] = [.one, .two].
Yeah; I haven't really settled on what the best style is for that. Be explicit in the first element or provide a type. I don't have any strong opinion on which is better. (Note that I wouldn't call your approach "casting." That's inaccurate and may cause confusion. You're providing an explicit type.) Looking at them side by side, I probably like yours a little better.
@RobNapier thanks for your answer. It is really awesome when somebody answers so in detail instead of setting down vote. By the way you have an bug in your answer on line let firstString = firstNames.map { $0.word }.joined(separator: ",") ---> Value of type String has no member 'joined'
@RobNapier to have answer without errors, you can change .joined(separator: ",") to .joinWithSeparator(",") :)
.joined(separator:) is the Swift 3 version. joinedWithSeparator() is the Swift 2.2 version. That's the only difference.
-2

My guess is that 'val' is temporary variable and can't be assign to so that it would affect the 'dict' dictionary.

Instead of

val = ..

try using

dict[key] = ... 

Also, it would be great if you would describe what you are trying to achieve with you code.

1 Comment

This will return Cannot assign through subscript subscript is get-only Also I think that, dict[key] will write to the dict, not to the variable that is on that position in the dict

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.