Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

470
Visualizações
Is Swift array reversed()[n] efficient or not?

When you call reversed() on an array in Swift, you get a ReverseCollection which merely wraps the original array with reversed access. Thus this is extremely efficient:

let arr = [1,2,3,4]
for i in arr.reversed() { print(i) }

Nothing actually got reversed except the access; the time complexity of reversed here is O(1). Cool!

But when I index into reversed() by an integer and check Quick Help, it appears I've lost all that efficiency; I'm shown the Sequence reversed() which generates a new array:

let arr = [1,2,3,4]
let i = arr.reversed()[1] // ???? this is a different `reversed()`!

And this seems to be true, because a reversed() array does not, itself, support indexing by number:

let arr = [1,2,3,4]
let rev = arr.reversed()
let i = rev[1] // compile error!

So my question is: is it really true that indexing by number into a reversed() array, as in my second example, loses the efficiency of the ReverseCollection index reversal?

over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

Yes, indexing by Int is causing you to lose your O(1) access into the reversed array. Quite the gotcha!

As you note, reversed() here is an overloaded method; on Array specifically, you have two definitions to choose from:

  1. BidirectionalCollection.reversed(), which returns a ReversedCollection, and
  2. Sequence.reversed(), which turns any sequence into a reversed [Element]

The overloading here is most confusing for Array itself, because it's the only Sequence type such that type(of: x) == type(of: x.reversed()).

The Swift type checker prefers more specific overloads over less-specific ones, so in general, the compiler will use the BidirectionalCollection overload instead of the Sequence one where possible. The rub: BidirectionalCollection has an opaque index type, and cannot be indexed using an Int; when you do index into the collection with an Int, the compiler is instead forced to choose the Sequence overload over the BidirectionalCollection one. This is also why your second code sample fails to compile: Swift code inference does not take into account surrounding context on other lines; on its own, rev is preferred to be a ReversedCollection<Array<Int>>, so attempting to index into it with an Int fails.

You can see this a little more clearly with the following:

func collType1<T: Collection>(_: T) {
    print(T.self) // ReversedCollection<Array<Int>>
    print(T.Index.self) // Index
}

func collType2<T: Collection>(_: T) where T.Index == Int {
    print(T.self) // Array<Int>
    print(T.Index.self) // Int
}

let x: [Int] = [1, 2, 3]
collType1(x.reversed())
collType2(x.reversed())

Lest you wonder whether the compiler can optimize around this when the fact of Int-based indexing appears to not have any other side effects, at the time of writing, the answer appears to be "no". The Godbolt output is a bit too long to reproduce here, but at the moment, comparing

func foo1(_ array: [Int]) {
    if array.reversed()[100] > 42 {
        print("Wow!")
    }
}

with

func foo2(_ array: [Int]) {
    if array.reversed().dropFirst(100).first! > 42 {
        print("Wow!")
    }
}

with optimizations enabled shows foo2 performing direct array access

cmp     qword ptr [rdi + 8*rax + 24], 43

having optimized away the ReversedCollection wrapper entirely, while foo1 goes through significantly more indirection.

over 4 years ago · Santiago Trujillo Relatório

0

Ferber explained the reason very well.

Here's an ad-hoc solution (which may not be preferred by everyone, because we are extending types from the standard library):

// RandomAccessCollection ensures fast index creation
extension ReversedCollection where Base: RandomAccessCollection {
  subscript(_ offset: Int) -> Element {
    let index = index(startIndex, offsetBy: offset)
    return self[index]
  }
}

[1, 2, 3].reversed()[0] // 3
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda