Skip to content

Instantly share code, notes, and snippets.

@jlogsdon
Forked from isa/gist:2571012
Created May 1, 2012 20:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jlogsdon/2571163 to your computer and use it in GitHub Desktop.
Save jlogsdon/2571163 to your computer and use it in GitHub Desktop.
Convert in less than 30 lines
Question: Convert following into the latter data structure in less than 30 lines:
List:
A, B, C
A, C, E
E, F, D
D, A, J
E, D, J
List
A, B, 1 (frequency)
A, C, 2
A, D, 1
A, E, 1
A, J, 1
B, C, 1
C, E, 1
D, E, 2
D, F, 1
D, J, 2
E, F, 1
E, J, 1
list = [
['A', 'B', 'C'],
['A', 'C', 'E'],
['E', 'F', 'D'],
['D', 'A', 'J'],
['E', 'D', 'J']
] # Or `.split("\n").map { |r| r.split(', ') }` if reading the exact contents
result = Hash.new(0) # All pairs start at a count of 0, prevents the need to ensure a key exists below
list.each do |row|
row.sort!
(row.length - 1).times do
leading = row.shift
row.each { |follow| result[(leading + follow).sort] += 1 }
end
end
@jrochkind
Copy link

interesting, I did it kinda differently (and mis-read and input and output actual strings instead of arrays), but still 5 lines. i'll add mine as a comment on your gist.

 counter = Hash.new(0)  # input on stdin
 $stdin.each_line do |line|
    line.split(',').collect {|s| s.strip}.combination(2).each {|combo| counter[combo.sort] += 1}
 end
 counter.keys.sort.each  {|combo| puts "#{combo.join(', ')}, #{counter[combo]}" }

update: Fixed to sort the combinations in output, as per the problem example

(You sure yours really counts combinations? It probably does, I haven't run yours. I ran mine! :) )

@jlogsdon
Copy link
Author

jlogsdon commented May 1, 2012

The comment I left after the list array is how I would parse it from STDIN or whatever. I had forgotten about combination... ruby's stdlib never ceases to amaze me.

Also, it turns out my solution doesn't order the pairs correctly, so you get "E,D" instead of "D,E" (I took out my sort on accident, derp)

@jrochkind
Copy link

mine ordered the pairs internally, but didn't order the list of pairs in output properly. fixed!

@jlogsdon
Copy link
Author

jlogsdon commented May 1, 2012

(You sure yours really counts combinations? It probably does, I haven't run yours. I ran mine! :) )

With the sort in there it works properly. I'm just shortening the array by 1 each loop and making pairs with the remaining elements, which is probably what Array#combination does in the background.

LIST A, B, C
LEADING A
LIST B, C
PAIR A, B
PAIR A, C
LEADING B
LIST C
PAIR B, C

is what it looks like I guess?

@jrochkind
Copy link

jrochkind commented May 1, 2012 via email

@isa
Copy link

isa commented May 1, 2012

Pretty cool guys.. Cheers!

@kejadlen
Copy link

kejadlen commented May 1, 2012

Here's mine:

data = [ %w[ A B C ],
         %w[ A C E ],
         %w[ E F D ],
         %w[ D A J ],
         %w[ E D J ] ]

hash = data.inject(Hash.new {|h,k| h[k] = 0 }) do |h,ary|
  ary.combination(2) {|c| h[c.sort] += 1 }
  h
end

hash.sort.each {|k,v| puts "#{k[0]}, #{k[1]}, #{v}" }

@snuxoll
Copy link

snuxoll commented May 1, 2012

A variation of the one posted above:

list = [
  ['A', 'B', 'C'],
  ['A', 'C', 'E'],
  ['E', 'F', 'D'],
  ['D', 'A', 'J'],
  ['E', 'D', 'J']
]

comb = (list.inject([]) { |a,ary| a + ary.combination(2).to_a.map(&:sort) }).sort
hash = Hash.new {|h,k| h[k] = comb.count(k)}
comb.uniq.each {|x| puts "#{x[0]}, #{x[1]}, #{hash[x]}"}

I saved a couple lines by dropping the longer do...end syntax, and taking advantage Hash#new taking a block in a slightly more useful way than the above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment