web-dev-qa-db-ja.com

Swift標準ライブラリのreverse()関数がReverseRandomAccessCollectionを返すのはなぜですか?

Swift(妥当なレベルまで)を学んだので、標準ライブラリを理解しようとしていますが、実際には、主にελληνικάです!

だから特定の質問:私は文字列の配列を持っていて、それに対してreverse()を呼び出すことができます。

let arr = ["Mykonos", "Rhodes", "Naxos"].reverse()

今では素朴に、これから一種の配列を取り戻すと思いました。 (たとえば、Rubyには、配列を渡して配列を取得するのと同様のメソッドがあります)

しかし、arrは実際にはタイプです

ReverseRandomAccessCollection<Array<String>>

これは実際には構造体であり、CollectionTypeに準拠しています。

public struct ReverseRandomAccessCollection<Base : CollectionType where Base.Index : RandomAccessIndexType> : _ReverseCollectionType

これは私がこれを行うことができることを意味します:

for item in arr {
  print(item)
}

でもできない

print(arr[0])

なぜこれがこのように設計されているのですか?

Swiftの辞書もCollectionTypeを実装しているので、これを行うことができます:

let dict = ["greek" : "Swift sometimes", "notgreek" : "Ruby for this example"].reverse()

しかし、辞書は配列のように順序付けられていないので、なぜ辞書でreverse()を呼び出すことができますか?

誰かが私を読んで改善できる方向に私を向けることができればボーナスポイントSwift stdlib foo、Ευχαριστώ!

19
Brynjar

これは、時間とメモリの両方のパフォーマンスの最適化です。 ReverseRandomAccessCollectionは、元の配列の要素を逆の順序で表示します。新しい配列を作成してすべての要素をコピーする必要はありません(元の配列が変更されていない場合)。

あなたcan添え字で逆の要素にアクセスします:

_let el0 = arr[arr.startIndex]
let el2 = arr[arr.startIndex.advancedBy(2)]
_

または

_for i in arr.indices {
    print(arr[i])
}
_

で明示的に配列を作成することもできます

_let reversed = Array(["Mykonos", "Rhodes", "Naxos"].reversed())
_

dictionaryも、キーと値のペアのシーケンスです。に

_let dict = ["greek" : "Swift sometimes", "notgreek" : "Ruby for this example"].reverse()
_

まったく異なるreversed()メソッドが呼び出されます。

_extension SequenceType {
    /// Return an `Array` containing the elements of `self` in reverse
    /// order.
    ///
    /// Complexity: O(N), where N is the length of `self`.
    @warn_unused_result
    public func reversed() -> [Self.Generator.Element]
}
_

結果は、辞書のキーと値のペアが逆の順序で並んだ配列になります。ただし、ディクショナリ内のキーと値のペアの順序は任意である可能性があるため、これは限られた用途です。

27
Martin R

ReverseCollentionの言語ドキュメント.reverse()の結果)から:

Reverse()メソッドは、双方向インデックスを持つコレクションに適用されると常に遅延しますが、その結果に適用されるアルゴリズムに暗黙的に遅延を与えることはありません。

言い換えると、双方向インデックスを持つ通常のコレクションcの場合:

  • c.reverse()は新しいストレージを作成しません

.。

したがって、ReverseRandomAccessCollectionまだ反転されていない配列に対するランダムアクセスラッパーとして見ることができます(つまり、元の配列arrはまだありませんコピーされ、メモリ内の新しい位置に反転されます)。

当然、上記から、逆コレクションに直接インデックスを付けることはできません。Arrayは配列を保持するメモリへのポインタとしてアクセスを提供し、インデックスはビット単位(タイプに応じて)に進むことに対応します。メモリ。ただし、ReverseRandomAccessIndexを使用して、配列インデックススタイルで「逆配列」の要素にアクセスすることはできます。

let arr = ["Mykonos", "Rhodes", "Naxos"]
let arrReverse = arr.reverse()
    /* ReverseRandomAccessCollection access "wrapper" over
       the 'arr' data in memory. No new storage allocated */

let myIndex = arrReverse.startIndex.advancedBy(2)
    /* bIndex type: 
       ReverseRandomAccessIndex<ReverseRandomAccessIndex<Index>> */

print(arrReverse[myIndex]) // "Mykonos"

逆に、逆配列にメモリを明示的に割り当てて、他の配列と同じように扱うことができます。この時点で、arrReversearrとは別の配列であり、それを使用して(一度)作成される以外は前者とは関係がありません。

let arr = ["Mykonos", "Rhodes", "Naxos"]
let arrReverse = Array(arr.reverse())
    /* Array<String> */

let myIndex = arrReverse.startIndex.advancedBy(2)
    /* bIndex type: Int */

print(arrReverse[myIndex]) // "Mykonos"

Martin Rは私を殴ったので、辞書に関する彼のメモを参照してください。

3
dfri

Swift 3.0を使用すると、インデックスを介して配列値に直接アクセスできます。

var streets = ["Albemarle", "Brandywine", "Chesapeake"]
streets = streets.reversed()
print("Array at index is \(streets[0])")

これは「チェサピーク」を印刷します

1
Sabby