单值多键字典-Swift

单值多键字典-Swift,swift,dictionary,Swift,Dictionary,我正在尝试创建一个应用程序,根据预先确定的映射,将英文字母映射到各种RNA密码子(A、C、U或G的序列,3个一组) 要将英语转换为RNA,字典如下所示: var englishTomRNA: [Character: [String]] = ["A": ["UUU", "UAC"], "Q": ["UUA"], "S": [

我正在尝试创建一个应用程序,根据预先确定的映射,将英文字母映射到各种RNA密码子(A、C、U或G的序列,3个一组)

要将英语转换为RNA,字典如下所示:

var englishTomRNA: [Character: [String]] = ["A": ["UUU", "UAC"],
                                            "Q": ["UUA"],
                                            "S": ["UCU", "UCC", "UCA"]]
等等

正如您所见,任何给定的英语字符(代表一个多基因基因型的生物学特征)都有多个值,我对转换这些值没有问题

然而,我在实现上确实有一个问题,那就是字典以另一种方式隐藏。我最初使用的
switch:case
语句如下:

    for codon in preEnglishInputString {
        switch codon {
            case "UUU", "UAC":               inEnglish.append("A")
            case "UUA":                      inEnglish.append("Q")
            case "UCU", "UCC", "UCA", "UCG": inEnglish.append("S")
        }
    }
但是,现在我希望将RNA->English转换函数转换为使用字典,以便更符合此实现

我不知道如何为一个值设置多个键(与上面使用的为一个键设置多个值相反)

尝试以下操作时,不起作用:

let mRNAtoEnglish: [[String] : Character] =
                                            [["UUU", "UAC"]       : "A",
                                            ["UUA", "UUG"]        : "Q",
                                            ["UCU", "UCC", "UCA"] : "S"]
当编译器大喊
时,类型[String]不符合协议“Hashable”

我只是使用了错误的数据结构,还是有一些语法我不知道?(我对斯威夫特还不太熟悉)


谢谢

不能将数组用于字典键。钥匙是独一无二的。同一个键在字典中不能出现两次,但不同的键可能指向同一个值。所有键必须为同一类型,所有值必须为同一类型

因此,正如Leo所评论的,使用相同的值保存3个键,而不是使用3个键保存单个数组:

let mRNAtoEnglish: [String : Character] =
    ["UUU": "A",
     "UAC": "A",
     "UUA": "Q",
     "UUG": "Q",
     "UCU": "S",
     "UCC": "S",
     "UCA": "S"]

使用Swift的高阶功能:

var englishTomRNA: [Character: [String]] = ["A": ["UUU", "UAC"],
                                            "Q": ["UUA"],
                                            "S": ["UCU", "UCC", "UCA"]]
var inEnglish = ""

// Sample Input
let preEnglishInputString = ["UUA", "UCC", "UUU"]

for codon in preEnglishInputString {
    let english = englishTomRNA
                        .filter { $0.1.contains(codon) }
                        .first!.0
    inEnglish.append(english)
}

print(inEnglish) // QSA
这需要两个假设:

  • 每个密码子代码映射到正好一个英文字符
  • preEnglishInputString
    中的每个密码子代码都是有效的,可以在您的
    englishTomRNA
    字典中找到

  • 它的作用是:
    .filter{…}
    查找包含
    密码子的任何键值对。在字典上调用
    filter
    时,它会退化为
    (键、值)
    的元组,因此
    $0.1
    指的是
    filter
    始终返回匹配数组,即使它只找到一个匹配

    首先从列表中获取第一个匹配项(假设1)。感叹号假设始终找到匹配项(假设2)


    .0
    获取键值对的键,该键值对包含英文字符。

    如果您想要基于词典的答案,这将生成与
    englishTomRNA
    相反的版本

    var englishTomRNA: [Character: [String]] = ["A": ["UUU", "UAC"],
                                                "Q": ["UUA"],
                                                "S": ["UCU", "UCC", "UCA"]]
    
    var mRNAtoEnglish = [String:Character]()
    for (key, value) in englishTomRNA {
        for mRNA in value {
            mRNAtoEnglish[mRNA] = key
        }
    }
    
    print(mRNAtoEnglish)
    // ["UUU": "A", "UCA": "S", "UCC": "S", "UAC": "A", "UUA": "Q", "UCU": "S"]
    

    只需使用相同的值保存3个键,而不是使用3个键保存单个数组keys@LeoDabus请参见luiyezheng的答案+我的评论以获取更新!查看我在James answer上的评论我很欣赏这个答案,但是@Code Different的答案允许我将字典转换为类变量并节省内存,并尝试使用更高阶的函数(来自Java背景,这些东西对我来说还是新的,还没有在我当前的CompSci类的版本8中使用它们). 谢谢你!键入另一本文字词典不仅可以节省内存,还可以增加出错的几率。让我们承认:输入技术数据是相当困难的。@code不同的是,整个字典总共包含64个密码子#ThankNuthForcOpyandPaste编写代码来解析第一个字典以生成第二个字典并不困难,这样就消除了更多键入错误的机会。如果您在长字符串密码子上调用此功能,重复过滤将花费大量时间。luiyezhang的基于词典的答案将表现得更好,并且在节省时间方面花费的内存量可以忽略不计。你的密码子数组必须非常长,大约一百万个密码子,执行时间才能有所不同。即使如此,我还是宁愿在代码中使用
    mRNAtoEnglish
    而不是在新的文字词典中键入。我的答案是以编程方式创建词典。
    englishTomRNA.forEach({(key,value)in value.forEach({mRNAtoEnglish[$0]=key})