enguerranws
enguerranws

Reputation: 8233

2 dimensions ordered numbers

I have a question, it can be very simple for you, but I don't know how to do it with a simple and a powerful solution.

So, let's consider we have a rectangle of numbers like that :

154784587
251436258
748541254
965874584
521414174

How can I crawl it to find horizontally or vertically multiples of 3 (e.g.) ? I thought about converting it to a 2 dimensions array :

var arr = [
  [1,5,4,7,8,4,5,8,7],
  ...
]

And then double loop into it (horizontal and vertical). But that sounds messy, do you know how I could achieve that in a clean and simple way ?

Upvotes: 0

Views: 45

Answers (1)

Pete
Pete

Reputation: 3254

Requirements

Based on your comments, this is what I understand:

  • Find all values divisible by 3 in both the horizontal and vertical direction
  • All values include the combination of all digits. For example, if a row contains 9 items, then all single digit, double digit, triple digit, ... 9 digit values must be considered.

Assumptions

I assumed that the input value would be a string and that map, reduce, and filter methods were available.

Input

var stream = "154784587251436258748541254965874584521414174";
var columns = 9;

Helpers

Three helpers were required:

  • One to group values together based on a string input.
  • One to return a character from a string.
  • One to create a predicate to test for values divisible by 3.
  • One to parse strings into integers and extract all divisible values.

Some of these functions look very simple, but were done to enhance the readability of the code:

function groupChars(stringValue, numberOfCharacters) {
    var regex = new RegExp(".{1," + numberOfCharacters + "}", "g");
    return stringValue.match(regex);
}

function getNthCharacter(stringValue, index) {
    return stringValue[index];
}

function isDivisibleBy(divisor) {
  return function(value) {
    return value % divisor === 0;
  }
}

function getValuesDivisibleBy(stringValues, divisor) {
    return stringValues.map(function(item) {
              return parseInt(item, 10);
          }).filter(isDivisibleBy(3));
}

Rectangular Data Generation

Using these helpers, row (or horizontal) data was captured by grouping characters together by the number of columns. Given a set of rows, the column (or vertical) data could then be extracted.

function getRowData(stream, columns) {
    return groupChars(stream, columns);
}

function getColumnData(rowData, columns) {
    var columnData = [];
    for (var i = 0; i < columns; i++) {
        columnData.push(rowData.map(function(row) {
            return row[i]
        }).join(''));
    }
    return columnData;
}

Create a flat array of horizontal and vertical values

Values were then extracted from the stream by first extracting the rows and then extracting the columns. This produced an array of strings that represent the row and columns values.

function getBoxedData(stream, columns) {
    var data = {};
    data.rows = getRowData(stream, columns);
    data.columns = getColumnData(data.rows, columns);
    return data.rows.concat(data.columns);
}

Reduce the data set

The final processing was done by taking each string and parsing it for numbers or groups of numbers based on the number of columns. A loop was required to group the values as single digit, double digit, and up to n-digit values. Each value was parsed as an integer and then verified for it's divisibility by 3.

var set = getBoxedData(stream, columns);

var results = set.reduce(function(result, item) {
    for(var i = 0; i < item.length;) {
        var values = groupChars(item, ++i);
        var valuesByDivisibleThree = getValuesDivisibleBy(values, 3);
        result.push.apply(result, valuesByDivisibleThree);
    }
    return result;
}, []);

The final result:

You can get all unique values by applying a filter to the final result.

var stream = "154784587251436258748541254965874584521414174";
var columns = 9;

function groupChars(stringValue, numberOfCharacters) {
  var regex = new RegExp(".{1," + numberOfCharacters + "}", "g");
  return stringValue.match(regex);
}

function getNthCharacter(stringValue, index) {
  return stringValue[index];
}

function isDivisibleBy(divisor) {
  return function(value) {
    return value % divisor === 0;
  }
}

function getRowData(stream, columns) {
  return groupChars(stream, columns);
}

function getColumnData(rowData, columns) {
  var columnData = [];
  for (var i = 0; i < columns; i++) {
    columnData.push(rowData.map(function(row) {
      return row[i]
    }).join(''));
  }
  return columnData;
}


function getValuesDivisibleBy(stringValues, divisor) {
  return stringValues.map(function(item) {
    return parseInt(item, 10);
  }).filter(isDivisibleBy(divisor));
}

function getBoxedData(stream, columns) {
  var data = {};
  data.rows = getRowData(stream, columns);
  data.columns = getColumnData(data.rows, columns);
  return data.rows.concat(data.columns);
}

var set = getBoxedData(stream, columns);

var results = set.reduce(function(result, item) {
  for (var i = 0; i < item.length;) {
    var values = groupChars(item, ++i);
    var valuesByDivisibleThree = getValuesDivisibleBy(values, 3);
    result.push.apply(result, valuesByDivisibleThree);
  }
  return result;
}, []);

console.log(results);
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>


Original Answer for Historic reasons:

Using 2D-Arrays

Maybe reduce and filter will clean it up? No loops required ... even though there are loops running in the background.

var dataset = [
  [1, 5, 4, 7, 8, 4, 5, 8, 7],
  [2, 5, 1, 4, 3, 6, 2, 5, 8],
  [7, 4, 8, 5, 4, 1, 2, 5, 4],
  [9, 6, 5, 8, 7, 4, 5, 8, 4],
  [5, 2, 1, 4, 1, 4, 1, 7, 4]
];

function isDivisibleBy(divisor) {
  return function(value) {
    return value % divisor === 0;
  }
}

var divisibleByThree = dataset.reduce(function(accumulator, row) {
  return accumulator.concat(row.filter(isDivisibleBy(3)));
}, []);

console.log(divisibleByThree)
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>

Parsing the string directly

Alternatively, you could just parse the string in and clean it up using regex. Using map and filter would also provide the same result. This would be the same solution if you had access to the data as a 1D-array.

var stream = "154784587251436258748541254965874584521414174";
var data = stream.split(/(?!^)/);

function isDivisibleBy(divisor) {
  return function(value) {
    return value % divisor === 0;
  }
}

var divisibleByThree = data.map(function(item) {
  return parseInt(item, 10);
}).filter(isDivisibleBy(3));

console.log(divisibleByThree);
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>

Upvotes: 1

Related Questions