2015-03-15 19 views
6

Ho una vasta gamma di oggetti e vorrei dividerlo in due array contenenti gli oggetti in ordine alternato.Divisione Big Array in due array

Esempio:

[0, 1, 2, 3, 4, 5, 6]

Diventa queste due matrici (dovrebbero alternano)

[0, 2, 4, 6] e [1, 3, 5]

Ci sono un sacco di modi per dividere un array. Ma, qual è il più efficiente (il meno costoso) se l'array è enorme.

+1

Il meglio che si vuole ottenere è 'O (n) '. Basta creare due nuovi array e scorrere il vecchio, alternando dove si mette un elemento su ogni iterazione. – royhowie

risposta

4

Ci sono vari modi fantastici per farlo con il filtro, ma la maggior parte richiederebbe probabilmente due passaggi piuttosto che uno, quindi potresti anche usare un ciclo for.

Prenotare lo spazio in anticipo potrebbe fare una grande differenza in questo caso, poiché se la sorgente è grande eviterà una ridistribuzione non necessaria man mano che i nuovi array cresceranno e il calcolo dello spazio necessario è in tempo costante sugli array.

// could make this take a more generic random-access collection source 
// if needed, or just make it an array extension instead 
func splitAlternating<T>(source: [T]) -> ([T],[T]) { 
    var evens: [T] = [], odds: [T] = [] 

    evens.reserveCapacity(source.count/2 + 1) 
    odds.reserveCapacity(source.count/2) 

    for idx in indices(source) { 
     if idx % 2 == 0 { 
      evens.append(source[idx]) 
     } 
     else { 
      odds.append(source[idx]) 
     } 
    } 

    return (evens,odds) 
} 

let a = [0,1,2,3,4,5,6] 
splitAlternating(a) // ([0, 2, 4, 6], [1, 3, 5]) 

Se le prestazioni sono veramente critica, è possibile utilizzare source.withUnsafeBufferPointer per accedere agli elementi di origine, per evitare i limiti Indice CONTROLLO.

Se gli array sono davvero enormi, e non si ha intenzione di utilizzare i dati risultanti, tranne per assaggiare un piccolo numero di elementi, si potrebbe considerare l'utilizzo di una vista pigro invece (anche se lo std LIB pigro isn filtro' t molto utile qui in quanto restituisce la sequenza non una raccolta - potrebbe essere necessario scrivere il proprio).

+0

Molte risposte estremamente ben informate fornite. Ho scelto questo perché va un po 'oltre spiegando i modi per migliorare le prestazioni. – Onichan

0

Utilizzare per cicli. Se il valore dell'indice è pari, invialo a un array e se il valore dell'indice è dispari, quindi invia tale array a dispari.

4

È possibile utilizzare l'per in stride ciclo per riempire due matrici risultanti come segue:

extension Array { 
    var groupOfTwo:(firstArray:[T],secondArray:[T]) { 
     var firstArray:[T] = [] 
     var secondArray:[T] = [] 
     for index in stride(from: 0, to: count, by: 2) { 
      firstArray.append(self[index]) 
      if index + 1 < count { 
       secondArray.append(self[index+1]) 
      } 
     } 
     return (firstArray,secondArray) 
    } 
} 



[0, 1, 2, 3, 4, 5, 6].groupOfTwo.firstArray // [0, 2, 4, 6] 
[0, 1, 2, 3, 4, 5, 6].groupOfTwo.secondArray // [1, 3, 5] 

aggiornamento: Xcode 7.1.1 • Swift 2,1

extension Array { 
    var groupOfTwo:(firstArray:[Element],secondArray:[Element]) { 
     var firstArray:[Element] = [] 
     var secondArray:[Element] = [] 
     for index in 0.stride(to: count, by: 2) { 
      firstArray.append(self[index]) 
      if index + 1 < count { 
       secondArray.append(self[index+1]) 
      } 
     } 
     return (firstArray,secondArray) 
    } 
} 
+0

Nel caso qualcuno stia guardando questo codice non funziona in Swift 2 .. stride (da: a: da :) non esiste e [T] è cambiato in [Elemento] – earthtrip

0

Ecco, a mio parere, il modo più semplice

old_list = [0, 1, 2, 3, 4, 5, 6] 
new_list1 =[] 
new_list2 = [] 
while len(old_list)>0: 
    new_list1.append(old_list.pop(-1)) 
    if len(old_list) != 0: 
     new_list2.append(old_list.pop(-1)) 

new_list1.reverse() 
new_list2.reverse() 
4

Un approccio più concisa, funzionale, sarebbe quella di utilizzare reduce

let a = [0,1,2,3,4,5,6] 

let (evens, odds) = a.enumerate().reduce(([Int](),[Int]())) { (cur, next) in 
    let even = next.index % 2 == 0 
    return (cur.0 + (even ? [next.element] : []), 
      cur.1 + (even ? [] : [next.element])) 
} 

evens // [0,2,4,6] 
odds // [1,3,5]