Como retornar uma parte de uma matriz em Ruby?

125

Com uma lista em Python, posso retornar uma parte dela usando o seguinte código:

foo = [1,2,3,4,5,6]
bar = [10,20,30,40,50,60]
half = len(foo) / 2
foobar = foo[:half] + bar[half:]

Como Ruby faz tudo em matrizes, me pergunto se há algo semelhante a isso.

Christian Stade-Schuldt
fonte

Respostas:

192

Sim, o Ruby tem uma sintaxe de fatiamento de matriz muito semelhante ao Python. Aqui está a ridocumentação para o método de índice de matriz:

--------------------------------------------------------------- Array#[]
     array[index]                -> obj      or nil
     array[start, length]        -> an_array or nil
     array[range]                -> an_array or nil
     array.slice(index)          -> obj      or nil
     array.slice(start, length)  -> an_array or nil
     array.slice(range)          -> an_array or nil
------------------------------------------------------------------------
     Element Reference---Returns the element at index, or returns a 
     subarray starting at start and continuing for length elements, or 
     returns a subarray specified by range. Negative indices count 
     backward from the end of the array (-1 is the last element). 
     Returns nil if the index (or starting index) are out of range.

        a = [ "a", "b", "c", "d", "e" ]
        a[2] +  a[0] + a[1]    #=> "cab"
        a[6]                   #=> nil
        a[1, 2]                #=> [ "b", "c" ]
        a[1..3]                #=> [ "b", "c", "d" ]
        a[4..7]                #=> [ "e" ]
        a[6..10]               #=> nil
        a[-3, 3]               #=> [ "c", "d", "e" ]
        # special cases
        a[5]                   #=> nil
        a[6, 1]                #=> nil
        a[5, 1]                #=> []
        a[5..10]               #=> []
Jeremy Ruten
fonte
5
por que um [5, 1] ​​é diferente de um [6, 1]?
dertoni
25
a[2..-1]para passar do terceiro elemento para o último. a[2...-1]para ir do terceiro elemento até o segundo último elemento.
Clever Programmer
1
Felicidades @ Rafeh, me perguntando como esse lixo funciona, -1 fez o truque
Ben Sinclair
A sintaxe do @CleverProgrammer está muito mais próxima do Python do que a resposta aceita. Eu amo Ruby, mas devo dizer que a sintaxe do Python é mais curta e clara. Como bônus, é possível especificar a etapa:range(10)[:5:-1]
Eric Duminil
27

Se você deseja dividir / cortar a matriz em um índice i,

arr = arr.drop(i)

> arr = [1,2,3,4,5]
 => [1, 2, 3, 4, 5] 
> arr.drop(2)
 => [3, 4, 5] 
Lenin Raj Rajasekaran
fonte
17

Você pode usar slice () para isso:

>> foo = [1,2,3,4,5,6]
=> [1, 2, 3, 4, 5, 6]
>> bar = [10,20,30,40,50,60]
=> [10, 20, 30, 40, 50, 60]
>> half = foo.length / 2
=> 3
>> foobar = foo.slice(0, half) + bar.slice(half, foo.length)
=> [1, 2, 3, 40, 50, 60]

A propósito, de acordo com o meu conhecimento, as "listas" do Python são implementadas de maneira dinâmica e com crescente crescimento. A inserção no início é em O (n), a inserção no final é amortizada O (1), o acesso aleatório é O (1).

Manuel
fonte
Você quer usar a matriz de barras na segunda fatia?
Samuel
FYI: slice!()não modifica a matriz no lugar, mas "Exclui os elementos fornecidos por um índice (opcionalmente até elementos de comprimento) ou por um intervalo". Por ruby-doc.org/core-2.2.3/Array.html#method-i-slice-21
Joshua Pinter
7

outra maneira é usar o método range

foo = [1,2,3,4,5,6]
bar = [10,20,30,40,50,60]
a = foo[0...3]
b = bar[3...6]

print a + b 
=> [1, 2, 3, 40, 50 , 60]
user3449311
fonte
3

Ruby 2.6 Intervalos sem começo / sem fim

(..1)
# or
(...1)

(1..)
# or
(1...)

[1,2,3,4,5,6][..3]
=> [1, 2, 3, 4]

[1,2,3,4,5,6][...3]
 => [1, 2, 3]

ROLES = %w[superadmin manager admin contact user]
ROLES[ROLES.index('admin')..]
=> ["admin", "contact", "user"]
PGill
fonte
2

Eu gosto de intervalos para isso:

def first_half(list)
  list[0...(list.length / 2)]
end

def last_half(list)
  list[(list.length / 2)..list.length]
end

No entanto, tenha muito cuidado se o terminal está incluído no seu intervalo. Isso se torna crítico em uma lista de tamanho ímpar, na qual você precisa escolher onde vai quebrar o meio. Caso contrário, você acabará contando duas vezes o elemento do meio.

O exemplo acima colocará consistentemente o elemento do meio na última metade.

labirinto
fonte
Você pode usar (list.length / 2.0).ceilpara colocar consistentemente o elemento do meio na primeira metade, se precisar.
Sorashi 03/03/19