shin
shin

Reputation: 32721

How to create an array of combination from array elements in Ruby

I have the following array.

@arr = ["A:c,b,a", "B:a,b,d", "C:a,c,b", "D:d,a,c", "a:A,C,D", "b:D,A,B", "c:B,A,C", "d:D,C,A"] 

I want to create an array with the combination of the letter before : and after :.

Output

["Ac,Ab,Aa", "Ba,Bb,Bd", "Ca,Cc,Cb", "Dd,Da,Dc", "aA,aC,aD", "bD,bA,bB", "cB,cA,cC", "dD,dC,dA"]

I have tried the following but it gives an error.

@arr.each { |item| name, choices =item.split(':')
            @names<<name
            @choices<<choices.strip
}
@combi = @name.product(@choices)

I appreciate any inputs. I thank you in advance.

=========

Full code

soshisoai.rb

class Soshisoai

  attr_reader :names, :choices, :arr, :combi

  def initialize 
    @arr=[]
    @names=[]
    @choices=[]
    file = File.new('soshisoai.txt', "r")
    file.each_line{|line| @arr<< line.strip }
    @arr.each { |item| name, choices =item.split(':')
                @names<<name
                @choices<<choices.strip
    }
    @combi = @name.product(@choices)

  end

end

soshisoai_spec.rb

require './spec_helper'
require './soshisoai.rb'

describe Soshisoai do

  specify{ expect(Soshisoai.new().arr).to eq ["A:c,b,a", "B:a,b,d", "C:a,c,b", "D:d,a,c", "a:A,C,D", "b:D,A,B", "c:B,A,C", "d:D,C,A"] }    
  specify{ expect(Soshisoai.new().names).to eq ["A", "B", "C", "D", "a", "b", "c", "d"] }
  specify{ expect(Soshisoai.new().choices).to eq ["c,b,a", "a,b,d", "a,c,b", "d,a,c", "A,C,D", "D,A,B", "B,A,C", "D,C,A"] }
  specify{ expect(Soshisoai.new().combi).to eq ["Ac,Ab,Aa", "Ba,Bb,Bd", "Ca,Cc,Cb", "Dd,Da,Dc", "aA,aC,aD", "bD,bA,bB", "cB,cA,cC", "dD,dC,dA"] }

end

soshisoai.txt

A:c,b,a
B:a,b,d
C:a,c,b
D:d,a,c
a:A,C,D
b:D,A,B
c:B,A,C
d:D,C,A

Upvotes: 0

Views: 95

Answers (3)

Alok Anand
Alok Anand

Reputation: 3356

@arr.each_with_object([]){|e, o| lhsStr, rhsStr = e.split(":");
o << rhsStr.split(",").map{|c| lhsStr + c}.join(",")}

#=> ["Ac,Ab,Aa", "Ba,Bb,Bd", "Ca,Cc,Cb", "Dd,Da,Dc",
     "aA,aC,aD", "bD,bA,bB", "cB,cA,cC", "dD,dC,dA"]

Upvotes: 0

Cary Swoveland
Cary Swoveland

Reputation: 110675

Yes, you can use Array#product:

Code

@arr.map { |str| lead, rest = str.split(':');
  [lead].product(rest.split(',')).map(&:join).join(',') } 

Explanation

@arr = ["A:c,b,a", "B:a,b,d", "C:a,c,b", "D:d,a,c",
        "a:A,C,D", "b:D,A,B", "c:B,A,C", "d:D,C,A"]

map first passes "A:c,b,a" to the block and this is assigned to the block variable:

str = "A:c,b,a"
lead, rest = str.split(':')
  #=> ["A", "c,b,a"]

so lead => "A" and rest => "c,b,a".

rest.split(',')
  #=> ["c", "b", "a"]

so

a = ["A"].product(["c", "b", "a"])
  #=> [["A", "c"], ["A", "b"], ["A", "a"]]

b = a.map(&:join)
  #=> ["Ac", "Ab", "Aa"]  

b.join(',')
  #=> "Ac,Ab,Aa"

After performing similiar calculations for each of the other elements of @arr, we obtain:

@arr.map { |str| lead, rest = str.split(':');
  [lead].product(rest.split(',')).map(&:join).join(',') } 
  #=> ["Ac,Ab,Aa", "Ba,Bb,Bd", "Ca,Cc,Cb", "Dd,Da,Dc",
  #    "aA,aC,aD", "bD,bA,bB", "cB,cA,cC", "dD,dC,dA"]

Upvotes: 1

sawa
sawa

Reputation: 168101

@arr.map do |e|
  before, afters = e.split(":")
  afters.split(",").map{|after| "#{before}#{after}"}.join(",")
end
# => ["Ac,Ab,Aa", "Ba,Bb,Bd", "Ca,Cc,Cb", "Dd,Da,Dc", "aA,aC,aD", "bD,bA,bB", "cB,cA,cC", "dD,dC,dA"]

Upvotes: 3

Related Questions