0

I want to group the array elements with their inner array group met

Input:

const arr = [
  [123, 243],
  [123, 435],
  [736, 987],
  [987, 774],
  [123, 666],
  [774, 999],
  [098, 980],
];

Output:

Result = [[123, 243, 435, 666],[736, 987, 774, 999],[098, 980]]

now you can find what i expect ?

I have tried this script but cant complete

function checkVal(array, value) {
  return array.map(function (entry, inx, arr) {
    if (Array.isArray(entry)) {
      return checkVal(entry, value);
    }
    if (entry === value) {
      return arr;
    } else {
      return null;
    }
  });
}
function multiDimensionalUnique(arr) {
  var uniques = [];
  var itemsFound = {};
  for (var i = 0, l = arr.length; i < l; i++) {
    var stringified = JSON.stringify(arr[i]);
    if (itemsFound[stringified]) {
      continue;
    }
    uniques.push(arr[i]);
    itemsFound[stringified] = true;
  }
  return uniques;
}
const arr = [
  [123, 243],
  [123, 435],
  [736, 987],
  [987, 774],
  [123, 666],
  [774, 999],
  [098, 980],
];
let firstTake = [];
// Expected Result = [[123, 243, 435, 666],[736, 987, 774, 999],[098, 980]]
let sTake = [];
let i = 0;
arr.forEach((innerArr) => {
  if (i == 0) firstTake.push(innerArr);
  innerArr.forEach((detailArr) => {
    let innerLoopArr = checkVal(arr, detailArr);
    innerLoopArr.forEach((innerLoopArrVal) => {
      var filtered = innerLoopArrVal.filter(el => el != null);
      sTake.push(filtered);
    });
  });
  i++;
});
let clearnArray = sTake.filter(v => v.length != 0);
console.log(multiDimensionalUnique(clearnArray));

Thanks in advance.

2 Answers 2

1

You could reduce them into array of objects and then check if some of the element in a tuple is in the reduce accumulator. Not sure if this is the most efficient way, but this should do:

const arr = [
  [123, 243],
  [123, 435],
  [736, 987],
  [987, 774],
  [123, 666],
  [774, 999],
  [098, 980],
];

const result = arr.reduce((acc, curr) => {
  let newAcc = acc;

  const currObj = {
    [curr[0]]: null,
    [curr[1]]: null,
  }
  
  for ([index, value] of newAcc.entries()) {
    if (curr.some(c => c in value)) {
    
      newAcc[index] = {
        ...value,
        ...currObj
      }
      
      return newAcc
    }
  }

  newAcc.push(currObj)
  
  return newAcc
}, []).map(obj => Object.keys(obj))

console.log(result)

Note that you may notice that the 098 becomes 98, this is not because of my code, but because in your original array 098 is detected as number, thus javascript converts it to a valid number (98). If you want to keep it as 098, you should make it array of strings.

Sign up to request clarification or add additional context in comments.

Comments

0

Seems like the array is a list of edges of a graph, and you're trying to get a list of sets of nodes in each disjoint graph.

This gets you the result you want:

arr.reduce((result, [a, b]) => {
    let g = result.find(g => g.has(a) || g.has(b));
    if (!g) result.push(g = new Set());
    g.add(a).add(b);
    return result;
}, []);

(If you want arrays at the end instead of Sets, you can add .map(s => Array.from(s)) to the end.)

But if you were to add another entry to the array like [736, 666], I'd think the first two sets should be merged. This handles that:

const result = arr.reduce((result, [a, b]) => {
    // Get all sets of nodes that contain either node
    let [g, ...gs] = [...result].filter(g => g.has(a) || g.has(b));
    // If none, make a new one
    if (!g) result.add(g = new Set());
    // Add both nodes to the set
    g.add(a).add(b);
    // Merge sets if there's more than one
    for (const h of gs) {
        for (const e of h) g.add(e);
        result.delete(h);
    }
    return result;
}, new Set());
console.log(Array.from(result, s => Array.from(s)));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.