0

I have a case where I want to store values in a dictionary, with the keys being a sequence of strings.

In Python, for example, I'd just use a tuple:

foo = {('a', 'b', 'c'): 10}

In Swift, though, dictionary keys must be Hashable, and tuples (being structs) aren't. Neither are arrays. (I know this, and therefore, this is different from the "In Swift can I use a tuple as the key in a dictionary?" question. The answer to that is clearly no.)

I could write my own class ListOfStrings: Hashable class that's just a [String], with its own hash code, but that seems like something I shouldn't be doing, in a high-level language.

I could use NSDictionary/NSArray, but that also seems like an awkward solution. Plus, the hash code of an NSArray is simply its length, which can't be good for performance.

Is there a better way to do this in Swift?

You
  • 54
  • 2
  • Would `NSMutableSet` or `NSSet` work? – l'L'l May 28 '16 at 04:35
  • l'L'l: Do you mean as a key? Besides losing the order of my strings, that appears to share all the problems as NSArray, including using the size as the hash code: http://opensource.apple.com//source/CF/CF-635.19/CFBasicHash.m – You May 28 '16 at 04:45
  • Yes, it's likely not going to work the way you want without doing some hacky thing to it perhaps. NSSet is generally faster though for checking member objects within it over NSArray. – l'L'l May 28 '16 at 04:47
  • appzYourLife: I don't think it's a duplicate. That question asks "Can you?" (and the answer is "No"). This question is "I know this thing isn't allowed, so what's the conventional way to solve it?" – You May 28 '16 at 13:32

1 Answers1

0

You could change your list of strings to a concatenation of strings, so rather than using:

foo ["a","b","c"] = someInteger

you would simply write it as:

foo ["a"+"b"+"c"] = someInteger

The dictionary is then just using Strings as keys and I'm guessing that nothing would have to change in the rest of your code. You'd have to handle the strings being used carefully to ensure that you always got a unique key, but I get the impression you've already got that covered.

Westside
  • 675
  • 1
  • 7
  • 16
  • I can't guarantee anything about the values of my strings, and this would hash `("a", "bc")` and `("ab", "c")` the same. Is there some character value I can put in a Swift String that isn't a valid Unicode character, which could be used as a separator? – You May 28 '16 at 13:28
  • That's tricky to answer without knowing the full context of what the contents of your data structure will be. I think all the characters in a string have to be unicode, but there might be something that you know wouldn't feature in the input strings (like and emoji for instance) that could be used. One thought: If you have no control over the strings, you will need to do something to ensure that each set is unique - maybe you could incorporate a solution to the above issue into that process. – Westside May 28 '16 at 19:31
  • The other issue is performance. I could join them with `"|"`, and if that character appears in the input, escape it by doubling it, and that would be safe. The downside is that it would mean for each key, instead of storing just references to existing strings, I'd need to build an entirely new string that's longer than all of them put together. – You May 28 '16 at 20:38