Finding the closest value from a matrix

I have a matrix that looks something like this

       85 90 100 125 150 175
8 1.183 1.118 1.006 0.805 0.671 0.575
10 1.847 1.744 1.57 1.256 1.047 0.897
12 2.659 2.511 .. .. ... ...
16 ... ... .. ... ... ..

Say, I have a value of 1.1, I want it to automatically choose the
closest bigger value i.e. 1.118 and say 8 mm diameter at 90 mm spacing.
How can this be implemented? I thought of creating hashes. but it seems
too complicated. If anyone is wondering about the formula it goes like
this.

value = 2 x area of circle / spacing

···

--
Posted via http://www.ruby-forum.com/.

Mahadev Ittina:

I have a matrix that looks something like this

       85 90 100 125 150 175
8 1.183 1.118 1.006 0.805 0.671 0.575
10 1.847 1.744 1.57 1.256 1.047 0.897
12 2.659 2.511 .. .. ... ...
16 ... ... .. ... ... ..

Say, I have a value of 1.1, I want it to automatically choose the
closest bigger value i.e. 1.118 and say 8 mm diameter at 90 mm
spacing. How can this be implemented? I thought of creating hashes.
but it seems too complicated. If anyone is wondering about the formula
it goes like this.

value = 2 x area of circle / spacing

Are the spacings restricted to 85, 90, 100, 125, 150 and 175?

Are the diameters restricted to 8, 10, 12 and 16?

Otherwise, do you have formulæ for how the diameters and spacings grow?

Otherwise the matrix is so small that maybe
you can generate and search it on runtime:

diameters = [8, 10, 12, 16]
spacings = [85, 90, 100, 125, 150, 175]
diameters.product(spacings).map { |d, s| [0.5 * Math::PI * d ** 2 / s, d, s] }.sort.find { |x,| x > 1.1 }
# => [1.11701072127637, 8, 90]

— Shot

···

--
I can picture in my mind a world without war, a world without hate. And
I can picture us attacking that world, because they’d never expect it.
                                                           [Jack Handy]

I have a matrix that looks something like this

      85 90 100 125 150 175
8 1.183 1.118 1.006 0.805 0.671 0.575
10 1.847 1.744 1.57 1.256 1.047 0.897
12 2.659 2.511 .. .. ... ...
16 ... ... .. ... ... ..

Say, I have a value of 1.1, I want it to automatically choose the
closest bigger value i.e. 1.118 and say 8 mm diameter at 90 mm spacing.
How can this be implemented? I thought of creating hashes. but it seems
too complicated. If anyone is wondering about the formula it goes like
this.

value = 2 x area of circle / spacing

This sounds an awful lot like homework.

If there is a finite list of spacings, you can figure out the ideal diameter for each one (by reversing the formula), round each up to the closest permited diamiter, and choose the one cooresponding to the smallest computed value (using the given formula). Look at Array#collect, Array#find, Array#sort, and Array#first.

-- MarkusQ

Create a one-dimensional array where each entry records the value, row
and column number (or row and column headers).

# This should be programmatically done by iterating your array
# not explicitly as I'm showing it here.
Descriptor = Struct.new :row, :col, :value
a = [
  Descriptor.new(0, 0, 1.183),
  Descriptor.new(0, 1, 1.118),
  Descriptor.new(0, 1, 1.006),
  # ..etc.
]

# Sort the array by value
a = a.sort_by{ |desc| desc.value }

# Create a method that finds the closest (larger) value in the array
# via a binary search: Binary search algorithm - Wikipedia
# (Left as an exercise for the reader.)

# Now you know what row and column it came from.

···

On Nov 21, 1:04 pm, Mahadev Ittina <mitt...@gmail.com> wrote:

I have a matrix that looks something like this

   85        90       100       125        150         175

8 1.183 1.118 1.006 0.805 0.671 0.575
10 1.847 1.744 1.57 1.256 1.047 0.897
12 2.659 2.511 .. .. ... ...
16 ... ... .. ... ... ..

Say, I have a value of 1.1, I want it to automatically choose the
closest bigger value i.e. 1.118 and say 8 mm diameter at 90 mm spacing.
How can this be implemented? I thought of creating hashes. but it seems
too complicated. If anyone is wondering about the formula it goes like
this.

Hello Thanks. They are limited to those spacings and those diameters, as
they are industry standards. However there are 5 more higher spacings.
So basically you are creating a map? That's filled with the values?
Thats quiet interesting. I tried the exact same thing, it says
"undefined method 'product' for for [8, 10, 12, 16]:Array"

···

--
Posted via http://www.ruby-forum.com/.

This sounds an awful lot like homework.

If there is a finite list of spacings, you can figure out the
ideal diameter for each one (by reversing the formula), round each up to
the closest permited diamiter, and choose the one cooresponding to
the smallest computed value (using the given formula). Look at
Array#collect, Array#find, Array#sort, and Array#first.

-- MarkusQ

I assure you, this is no homework. I am complete newbie, and I am
creating a plug-in to work with SketchUp. I could email it you if you
would like to see.

···

--
Posted via http://www.ruby-forum.com/\.

thanks for all the methods. I never realised there were so many ways to
do it!
I decided to do the 1st method. I have repeat the method a couple of
more times than shown here.. Its a good way.

reinforcement = [6, 8, 10, 12, 16, 20, 25, 32, 40]
number = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
diameters = [8, 10, 12, 16]
spacings = [85, 90, 100, 125, 150, 175, 200, 225, 250, 275, 300]
@shear_links = diameters.product(spacings).map { |d, s| [0.5 * Math::PI
* d ** 2 / s, d, s] }.sort.find { |x,| x > @asw_s }
@compression = reinforcement.product(number).map { |r, n| [0.25 *
Math::PI * r ** 2 * n, r, n] }.sort.find { |x,|x > @comp_steel}
@tension = reinforcement.product(number).map { |r, n| [0.25 * Math::PI *
r ** 2 * n, r, n] }.sort.find { |x,|x > @ten_steel}

···

--
Posted via http://www.ruby-forum.com/.

Mahadev Ittina:

They are limited to those spacings and those diameters, as they
are industry standards. However there are 5 more higher spacings.

That’s ok, then the matrix is small enough to be kept in memory
(and you can pregenerate it and only search on runtime, of course):

# pregenerate
diameters = [8, 10, 12, 16]
spacings = [85, 90, 100, 125, 150, 175] # extend as needed
values = diameters.product(spacings).map { |d, s| [0.5 * Math::PI * d ** 2 / s, d, s] }.sort

# search
values.find { |x,| x > 1.1 } # => [1.11701072127637, 8, 90]
values.find { |x,| x > 2 } # => [2.26194671058465, 12, 100]

So basically you are creating a map? That's filled with the values?

I’m mapping every diameter+spacing pair to [value, diameter, spacing]
triple, then I’m sorting the triples and picking the first one with the
first element (the value) larger than the desired input.

Thats quiet interesting. I tried the exact same thing, it says
"undefined method 'product' for for [8, 10, 12, 16]:Array"

The above works in Ruby 1.8.7 and 1.9.1.

If you run an earlier Ruby 1.8 version, you can either use the
backports gem¹ or implement a simple variation tailored to your case:

class Array
  def product other
    inject() do |result, my|
      result.concat other.map { |their| [my, their] }
    end
  end unless method_defined? :product
end

[:a, :b].product [:c, :d]
# => [[:a, :c], [:a, :d], [:b, :c], [:b, :d]]

¹ GitHub - marcandre/backports: The latest features of Ruby backported to older versions.

— Shot

···

--
Deleted code is debugged code.
                 [Jeff Sickel]

There's a few options.

The simplest is just to iterate through the whole thing, remembering:
  * The location of the closest larger value you've previously seen
  * How close that value was

For each value, if it is larger, see how close it is; if it's closer than
your previous best guess, it becomes your new best guess. At the end of
the process, you have the best guess.

-s

···

On 2009-11-21, Mahadev Ittina <mittina@gmail.com> wrote:

Hello Thanks. They are limited to those spacings and those diameters, as
they are industry standards. However there are 5 more higher spacings.
So basically you are creating a map? That's filled with the values?
Thats quiet interesting. I tried the exact same thing, it says
"undefined method 'product' for for [8, 10, 12, 16]:Array"

--
Copyright 2009, all wrongs reversed. Peter Seebach / usenet-nospam@seebs.net
| Seebs.Net <-- lawsuits, religion, and funny pictures
Fair game (Scientology) - Wikipedia <-- get educated!

Mahadev Ittina:

thanks for all the methods. I never
realised there were so many ways to do it!

I decided to do the 1st method. I have repeat the method
a couple of more times than shown here.. Its a good way.

reinforcement = [6, 8, 10, 12, 16, 20, 25, 32, 40]
number = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
diameters = [8, 10, 12, 16]
spacings = [85, 90, 100, 125, 150, 175, 200, 225, 250, 275, 300]
@shear_links = diameters.product(spacings).map { |d, s| [0.5 * Math::PI * d ** 2 / s, d, s] }.sort.find { |x,| x > @asw_s }
@compression = reinforcement.product(number).map { |r, n| [0.25 * Math::PI * r ** 2 * n, r, n] }.sort.find { |x,|x > @comp_steel}
@tension = reinforcement.product(number).map { |r, n| [0.25 * Math::PI * r ** 2 * n, r, n] }.sort.find { |x,|x > @ten_steel}

How about some DRY-ing up of the code (and
not recomputing the arrays every time)? :slight_smile:

def values rows, cols, &formula
  rows.product(cols).map do |row, col|
    [formula.call(row, col), row, col]
  end.sort
end

reinforcement = [6, 8, 10, 12, 16, 20, 25, 32, 40]
number = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
diameters = [8, 10, 12, 16]
spacings = [85, 90, 100, 125, 150, 175, 200, 225, 250, 275, 300]

@ds ||= values(diameters, spacings) { |d, s| 0.5 * Math::PI * d ** 2 / s }
@rn ||= values(reinforcement, number) { |r, n| 0.25 * Math::PI * r ** 2 * n }

@shear_links = @ds.find { |x,| x > @asw_s }
@compression = @rn.find { |x,| x > @comp_steel }
@tension = @rn.find { |x,| x > @ten_steel }

— Shot

···

--
Your lust for power doomed 700 men to a watery grave. Yes, you sank
my battleship – but at what cost to your soul? Now go to your room.
                                               [Joshua Green Allen]