Mike
Mike

Reputation: 398

Ruby array manipulation (Ruby 1.8 and Rails 2.2)

I'm hopelessly trying to write a method to manipulate an array in ruby. I'm trying to generate all in-order permutations of an array where each item is in turn replaced by an outside item. An example...

Given input:

arr = ["a", "b", "c"]

Desired output:

newArr = [ ["a", "b", "c"], ["a", "b", "*"], ["a", "*", "c"], ["a", "*", "*"], ["*", "b", "c"], ["*", "b", "*"], ["*", "*", "c"], ["*", "*", "*"] ]

Any help would be greatly appreciated. Thank you!

Upvotes: 2

Views: 1694

Answers (3)

glenn mcdonald
glenn mcdonald

Reputation: 15478

I don't understand your example order, either, but ignoring that, here's a solution in one line:

(0...(2**a.size)).map {|x| (0...a.size).map {|y| x & 2**y == 0 ? a[y] : val}}

Upvotes: 8

Bkkbrad
Bkkbrad

Reputation: 3137

Similar to oylenshpeegui's method:

def toggle(arr, sub)
  format = "%0#{arr.length}b"
  (0...2**(arr.length)).to_a.map do |i|
    sprintf(format,i).split('').zip(arr).map { |x| x[0] == "0" ? x[1] : sub }
  end
end

The split/zip combo matches each digit of the binary expansion of the index with the element it is selecting. The map at the end uses the digit to decide if it should return the array element or the substitution.

Upvotes: 1

oylenshpeegul
oylenshpeegul

Reputation: 3424

I'm not sure permutation is the right word. If you count in binary, then you are replacing the things if there is a one. Here's that in Ruby:

def mike(arr, sub)
  format = sprintf("%%0%db", arr.length)
  m = Array.new
  0.upto(2**arr.length-1) { |i|
    bits = sprintf(format, i).split('')
    a = Array.new
    0.upto(arr.length-1) { |j|
      if bits[j] == '0' then
        a << arr[j]
      else
        a << sub
      end
    }
    m[i] = a
  }
  return m
end

arr = ["a", "b", "c"]

p mike(arr, '*')

Is that if-then-else better with a ternary operator?

a <<= bits[j] == '0' ? arr[j] : sub

There must be a cleverer (or, at least more Rubyesque) way to do this, but it seems to produce the desired output.

ETA: Oops! My second and third items don't agree with yours. I guess I don't know what order you mean.

Upvotes: 2

Related Questions