skip to Main Content
let input = [
  [[1, 4], [40, 4]],
  [[1, 5], [40, 5]],
  [[4, 7], [4, 24]],
  [[1, 9], [4, 1]],
  [[1, 2], [6, 4]],
  [[80, 4], [90, 4]],
  [[4, 1], [4, 40]],
  [[4, 35], [4, 29]],
  [[4, 28], [4, 35]],
  [[5, 3.6], [9, 5.2]],
]; // Input
Output = [
  [[[1, 4], [40, 4]], [[80, 4], [90, 4]]],
  [[[1, 5], [40, 5]]],
  [[[4, 7], [4, 24]], [[4, 1], [4, 40]]],
  [[[4, 35], [4, 29]], [[4, 28], [4, 35]]],
  [[[1, 9], [4, 1]]],
  [[[1, 2], [6, 4]], [[5, 3.6], [9, 5.2]]],
];

If given an input of series of each start and end coordinates of a line, for example, [[1,4],[40,4]] means that it has 2 points connecting [1,4] and [40,4] to form a straight line. My objective now is to group all those lines which share the same equation y=mx+c, together into a nested array as shown above. For example,

[[1,4],[40,4]] and [[80,4],[90,4]] share the same linear equation y=4

[[4,7],[4,24]],[[4,1],[4,40]]      share the same linear equation x=4

 [[1,2],[6,4]] and [[5,3.6],[9,5.2]]  share the same linear equation y=0.4x+1.6

[[1,9],[4,1]]   is alone and it has the linear equation of -2.67x+11.67

Here is my working codepen demo

I know how to code out to find those m and c in y=mx+c, but the problem is when for example,[[4,7],[4,24]] and [[4,1],[4,40]] , the m gradient becomes infinity which unsolvable.

Can anyone please guide me on this on how to get the correct output?

2

Answers


  1. You can calculate the slope equation for each set of points and assign it to each array item, then group:

    const input=[[[1,4],[40,4]],[[1,5],[40,5]],[[4,7],[4,24]],[[1,9],[4,1]],[[1,2],[6,4]],[[80,4],[90,4]],[[4,1],[4,40]],[[4,35],[4,29]],[[4,28],[4,35]],[[5,3.6],[9,5.2]]];
    
    const inputsWithSlope = input.map((points) => {
      const [[x, y], [x1, y1]] = points;
      const slope = (y1 - y) / (x1 - x)
      const b = y1 - slope * x1
      return {
        points,
        line: x1 == x ? `x = ${x}` : `y = ${slope}x + ${b}`
      }
    })
    
    const res = inputsWithSlope.reduce((acc, curr) => {
      const accProp = acc[curr.line]
      acc[curr.line] = !accProp ? [curr.points] : [...accProp, curr.points]
      return acc
    }, {})
    const result = Object.values(res)
    result.forEach(e => console.log(JSON.stringify(e)))

    To deal with the rounding issue, you’ll have to round it:

    const input=[[[1,4],[40,4]],[[1,5],[40,5]],[[4,7],[4,24]],[[1,9],[4,1]],[[1,2],[6,4]],[[80,4],[90,4]],[[4,1],[4,40]],[[4,35],[4,29]],[[4,28],[4,35]],[[5,3.6],[9,5.2]]];
    
    const inputsWithSlope = input.map((points) => {
      const [[x, y], [x1, y1]] = points;
      const slope = (y1 - y) / (x1 - x)
      const b = y1 - slope * x1
      return {
        points,
        line: x1 == x ? `x = ${x}` : `y = ${slope.toFixed(2)}x + ${b.toFixed(2)}`
      }
    })
    
    const res = inputsWithSlope.reduce((acc, curr) => {
      const accProp = acc[curr.line]
      acc[curr.line] = !accProp ? [curr.points] : [...accProp, curr.points]
      return acc
    }, {})
    const result = Object.values(res)
    result.forEach(e => console.log(JSON.stringify(e)))
    Login or Signup to reply.
  2. Here’s my take at it. The strategy is to first get a description of the line for each pair of points, and then group those together into a map of maps, first keyed by slopes, and then by intercepts (either x or y, depending on if the line is vertical or not), and then extract the groups into a single array.

    let input=[ [[1,4],[40,4]] , [[1,5],[40,5]] , [[4,7],[4,24]] ,[[1,9],[4,1]], [[1,2],[6,4]], [[80,4],[90,4]] , [[4,1],[4,40]] , [[4,35],[4,29]] , [[4,28],[4,35]] ,[[5,3.6],[9,5.2]] ] ; 
    
    // a function to get the slope and intercept of the line formed by a pair of points
    function describeLine([[x1, y1], [x2, y2]]) {
      if (x1 == x2) { // vertical line
        return {m: "vertical", x: x1}
      }
      const p1 = x1 > x2 ? { x: x1, y: y1 } : { x: x2, y: y2 }
      const p2 = x1 < x2 ? { x: x1, y: y1 } : { x: x2, y: y2 }
      
      const m = (p1.y - p2.y) / (p1.x - p2.x)
      const y = y1 - m * x1
      return { m, y }
    }
    
    // this runs through the input array and accumulates all the pairs of points into a dictionary structure keyed by slope and then intercept
    // so for a line with slope 2 and y-intercept 3, it would go into the map at { 2 : { 3: [[ [point 1], [point2]] ], [ line 2 with same props] ...
    const maps = input.reduce((acc, line) => {
        const desc = describeLine(line)
        const m = acc[desc.m] || { }
        if (desc.x) { // vertical line
          x = m[desc.x] || []
          return { ...acc, [desc.m]: { ...m, [desc.x]: [ ...x, line ]}}
        } else {
          y = m[desc.y] || []
          return { ...acc, [desc.m]: { ...m, [desc.y]: [ ...y, line ]}}
        }
    }, {})
    
    // once we've accumulated that structure, we can just collect the individual arrays into one big array
    const sameLines = Object.values(maps).flatMap(Object.values)
    console.log(JSON.stringify(sameLines, null, 2))
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search