Sort an object and remove duplicates - javascript

Given an object like this. How to write a function that will return the object with sorted keys and remove the duplicates from the first value
e.g
const initialObj={
"2": ["A", "B", "D", "A"],
"1": ["A", "B", "C"],
};
const output = {
"1": ["C"],
"2": ["A", "B", "D"],
}
initial = {
"1": ["C", "F", "G"],
"2": ["A", "B", "C"],
"3": ["A", "B", "D"],
}
output = {
"1": ["F", "G"],
"2": ["C"],
"3": ["A", "B", "D"],
}

const initialObj= {
"1": ["C", "F", "G"],
"2": ["A", "B", "C"],
"3": ["A", "B", "D"],
}
function sortAndRemove(obj) {
var keys = Object.keys(obj)
keys.sort().reverse()
seenBefore = new Set()
answer = {}
for (var key of keys) {
for (var value of obj[key]) {
if (!seenBefore.has(value)) {
answer[key] = [...(answer[key] || []), value]
seenBefore.add(value)
}
}
}
return answer
}
console.log(sortAndRemove(initialObj))

Considering the case that I got the algorithm you described, the following snippet would do the trick:
const initial1 = {
"2": ["A", "B", "D", "A"],
"1": ["A", "B", "C"],
};
const initial2 = {
"1": ["C", "F", "G"],
"2": ["A", "B", "C"],
"3": ["A", "B", "D"],
}
// removing duplicates from array
const removeDuplicates = ({
arr,
toRemove
}) => {
return arr.filter(char => !toRemove.includes(char))
}
// returns a sorted array!
const sortObjKeys = (obj) => {
const entries = Object.entries(obj)
const sorted = entries.sort(([key1], [key2]) => {
return Number(key1) - Number(key2)
})
return sorted
}
// iterating over the sorted array (starting from the end)
const reducer = (sorted) => {
const {
ret
} = sorted.reverse().reduce((a, [key, val]) => {
const cleared = removeDuplicates({
arr: [...new Set([...val])],
toRemove: a.toRemove
})
a.ret = [
[key, cleared], ...a.ret,
]
a.toRemove = [...new Set([...a.toRemove, ...val])]
return a
}, {
ret: [],
toRemove: []
})
return ret
}
// putting it all together
const processSortedArr = (obj) => {
const sorted = sortObjKeys(obj)
const ret = reducer(sorted)
return Object.fromEntries(ret)
}
console.log('output1', processSortedArr(initial1))
console.log('output2', processSortedArr(initial2))

Here is a set of tools
Assuming the keys are strings and not numbers
If you want numerical sort, we need to cast to int
const deDupe = (arr1,arr2) => arr1.filter(val => !arr2.includes(val));
const sortDedupe = obj => {
const newObj = {}
const order = Object.keys(obj); // get the keys
order.sort(); // sort them
order.forEach(key => newObj[key] = obj[key]); // reorder the object
for (let i=0;i<order.length-1;i++) {
newObj[order[i]] = deDupe(newObj[order[i]],newObj[order[i+1]]); //dedupe based on next
}
const last = order.pop()
newObj[last] = [...new Set(newObj[last])]; // dedupe last
return newObj
}
const initialObj={
"2": ["A", "B", "D", "A"],
"1": ["A", "B", "C"],
}; /*
const output = {
"1": ["C"],
"2": ["A", "B", "D"],
}*/
const initial = {
"1": ["C", "F", "G"],
"2": ["A", "B", "C"],
"3": ["A", "B", "D"],
}
/*
output = {
"1": ["F", "G"],
"2": ["C"],
"3": ["A", "B", "D"],
}*/
let output1 = sortDedupe(initialObj)
console.log(output1)
let output2 = sortDedupe(initial)
console.log(output2)

Related

How to remove duplicates array in multidimensional array where the key positions might not same in JavaScript?

let originalArray = [
["A", "B", "C"],
["B", "A", "C"],
["D", "E", "F"]
];
let uniqueArray = originalArray.filter((item, index, self) => {
return index === self.findIndex((t) => JSON.stringify(t) === JSON.stringify(item));
});
console.log(uniqueArray);
I want this result:
[
["A", "B", "C"],
["D", "E", "F"]
];
To remove duplicates from a multidimensional array in JavaScript, where the key positions might not be the same, you can use a combination of Array.prototype.map(), Array.prototype.filter(), and Array.prototype.includes() to create a new array with only unique elements.
You can use an object with Array.prototype.reduce, storing a stringified version of the sorted values as the cache.
let originalArray = [
["A", "B", "C"],
["B", "A", "C"],
["D", "E", "F"]
];
let uniqueArray = Object.values(originalArray.reduce((acc, cur) => {
const data = [...cur].sort();
const key = JSON.stringify(data);
acc[key] = acc[key] ?? cur;
return acc;
}, {}));
console.log(uniqueArray);
You can sort the inner arrays before inserting them into a Set for filtering.
let originalArray = [
["A", "B", "C"],
["B", "A", "C"],
["D", "E", "F"]
];
let vis = new Set;
let res = originalArray.filter(x => {
const str = JSON.stringify([...x].sort());
return !vis.has(str) && vis.add(str);
});
console.log(res);

How to change places in an Array?

There's a list of 5 elements. Per default, the list (array) should show ["A", "B", "C", "D", "E"]. Every second the elements should rotate by one position:
List after 1 second: ["B", "C", "D", "E", "A"];
After 2 seconds: ["C", "D", "E", "A", "B"];
After 3 seconds: ["D", "E", "A", "B", "C"];
I'm learning and I need help. How would you solve this problem? This is my incorrect solution:
const testArray = ["A", "B", "C", "D", "E"];
const swap = function(theArray, indexA, indexB) {
let temp = theArray[indexA];
theArray[indexA] = theArray[indexB];
theArray[indexB] = temp;
};
swap(testArray, 0, 1);
console.log(testArray);
For no reason other than it's stupidly short.
let r = ['A','B','C','D','E'];
setInterval(_ => {r.push(r.shift());console.log(r)},1000)
You can try array.shift method:
const arr = [1, 2, 3, 4, 5];
setInterval(() => {
const firstElement = arr.shift();
arr.push(firstElement);
console.log(arr);
}, 1000);
this is a shorter version of the swap
const testArray = ["A", "B", "C", "D", "E"];
const swap = function(theArray) {
theArray.push(theArray.shift())
};
swap(testArray);
console.log(testArray);
You can shift the first element off the array, and then push it to the end of the array.
const arr = ['A', 'B', 'C', 'D', 'E'];
function swap(arr) {
// Log the joined array
console.log(arr.join(''));
// `shift` the first element off the array
// and `push` it back on
arr.push(arr.shift());
// Repeat by calling `swap` again after
// one second, passing in the updated array
setTimeout(swap, 1000, arr);
}
swap(arr);
Addition documentation
setTimeout

Sum string arrays and subarrays in javascript without concatenating them

I am trying to "sum" the items from one array to another, preserving their children (subarrays):
array1 = [ array2 = [ array3 = [
[ [ [
"A", "1", "A",
"B", "2", "B",
[ [ "1",
"C" + "3" = "2",
] ] [
], ], "C",
"D" "4" "3"
] ] ]
],
"D",
"4"
]
Edit: Ideally the longest array would be treated as the "main" array (its values ​​would come before the shortest array).
If the arrays have the same number of elements, the first array is the main.
["a", ["b", "c"], "d"]
+
["x", ["v", "w"], "y"]
=
["a" "x", ["b", "c", "v", "w"], "d", "y"]
["a", "b", ["c", "d", ["e", "f"]]]
+
[["1", ["2"]]]
=
["a", "b", ["c", "d", "1", ["e", "f", "2"]]]
Would it be possible? so far the only suggestions I've found are related to the use of .concat(), however it concatenates one array at the end of the other, and does not merge both:
var array1 = [["A", "B", ["C"]], "D"];
var array2 = [["1", "2", ["3"]], "4"];
console.log(array1.concat(array2)) // returns [["A", "B", ["C"]], "D", ["1", "2", ["3"]], "4"]
Edit 2:
I've been thinking about the problem in a different way now, and realized that an easy way to visualize it is like this:
target = [
"A",
"B",
[
"C",
"D",
[
"E"
],
"J"
]
]
I want to add the following element after "E":
newelement = [
[
[
"F",
[
"G",
"H",
"I"
]
]
]
]
the result would be:
result = [
"A",
"B",
[
"C",
"D",
[
"E",
"F",
[
"G",
"H",
"I"
]
],
"J"
]
]
so that's basically it, merging one array with another.
If I understand correctly you want to concat subsections of both arrays that consist only of non-arrays (the number of elements may differ), then merge the next arrays of both recursively, and then apply again the first logic to the next subsections having no arrays... etc.
Here is that idea implemented:
function deepConcat(a, b) {
if (a.length < b.length) return deepConcat(b, a);
let i = 0, j = 0, result = [];
while (true) {
while (i < a.length && !Array.isArray(a[i])) result.push(a[i++])
while (j < b.length && !Array.isArray(b[j])) result.push(b[j++])
if (i >= a.length || j >= b.length) break;
result.push(deepConcat(a[i++], b[j++]));
}
return [...result, ...a.slice(i), ...b.slice(j)];
}
const test = (a, b) => console.log(JSON.stringify(deepConcat(a, b)));
test([["A", "B", ["C"]], "D"], [["1", "2", ["3"]], "4"]);
test(["a", ["b", "c"], "d"], ["x", ["v", "w"], "y"]);
test(["a", "b", ["c", "d", ["e", "f"]]], [["1", ["2"]]]);
test(["A","B",["C","D",["E"],"J"]], [[["F",["G","H","I"]]]]);
Something like this?
array1 = [
["A", "B", ["C"]], "D"
]
array2 = [
["1", "2", ["3"]], "4"
]
array3 = [
["A", "B", "1", "2", ["C", "3"]], "D", "4"
]
const findFirstNonPrimitiveIndex = arr => arr.findIndex(x => !isPrimitive(x))
const takePrimitives = (arr, pos = 0) => arr.slice(0, findFirstNonPrimitiveIndex(arr))
const isPrimitive = x => typeof x !== "object"
const merge = (arr1, arr2) => {
const [head1, ...rest1] = arr1
const [head2, ...rest2] = arr2
// base case
if (rest1.length === 0)
if (isPrimitive(head1)) return [head1, head2];
else return [merge(head1, head2)]
// inductive step
if (isPrimitive(head1)) {
const cutPoint = findFirstNonPrimitiveIndex(rest1);
return [
...takePrimitives(arr1),
...takePrimitives(arr2),
...merge(rest1.slice(cutPoint), rest2.slice(cutPoint))
]
} else {
return [merge(head1, head2), ...merge(rest1, rest2)];
}
}
const result = merge(array1, array2);
console.log(result)
.as-console-wrapper {
top: 0;
max-height: 100% !important;
}

Use index of array to find the corresponding index in a filtered version of that array

Given the following array:
const arr = ["a", "c", "b", "c", "b"]
And given an index of 4, how can we return the index of the corresponding element in ["b", "b"]? In this example, the answer is 1.
More generally, how can we use the index of arr to find the corresponding index of b in arr2 where const arr2 = arr.filter(item => item === "b")?
Examples:
["a", "c", "b", "c", "b"][4] corresponds to ["b", "b"][1]
["a", "c", "b", "c", "b", "b"][4] corresponds to ["b", "b", "b"][1]
Inputs and expected outputs
function getCorrespondingIndexInFilteredArray(array, index, filterValue) {...}
getCorrespondingIndexInFilteredArray(["a", "c", "b", "c", "b"], 4, "b") // 1
getCorrespondingIndexInFilteredArray(["a", "c", "b", "c", "b", "b"], 4, "b") // 1
getCorrespondingIndexInFilteredArray(["b", "b"], 0, "b") // 0
getCorrespondingIndexInFilteredArray(["b", "b"], 1, "b") // 1
getCorrespondingIndexInFilteredArray(["a", "a"], 0, "b") // either 0 or -1 is alright here
You can use slice() upto the given index and then get the count of elements which are equal to element at given index.
const arr = ["a", "b", "c", "b"]
const other = (arr, ind) => {
return arr.slice(0,ind).reduce((ac, a) => a === arr[ind] ? ac + 1: ac, 0);
}
console.log(other(arr,3))
console.log(other(arr,1))
You could use a counter object and a for loop
function customIndex(arr, index) {
const counter = {};
for (let i = 0; i < arr.length; i++) {
counter[arr[i]] = counter[arr[i]] + 1 || 0;
if (index === i)
return counter[arr[i]]
}
return 'index out of bound'
}
console.log(customIndex(["a", "b", "c", "b"], 3))
console.log(customIndex(["a", "a", "b", "a"], 3))
console.log(customIndex(["a", "a", "b", "a"], 1))
You could filter the array to get the items which match arr[index] but only until index. (This will not short circuit like this first snippet)
const customIndex = (arr, index) =>
arr.filter((n, i) => n === arr[index] && i <= index).length - 1
console.log(customIndex(["a", "b", "c", "b"], 3))
console.log(customIndex(["a", "a", "b", "a"], 3))
console.log(customIndex(["a", "a", "b", "a"], 1))

js: how to filter out the repeat item from a two dimensional Array?

Is there any way can solve the below problem:
this is the origin data:
var m = [["a", "b"], ["c", "d", "e"], ["f", "g", "h"]]
var n = ["a","d","e", "h"]
I want to get the data:
[["a"], ["d","e"], ["h"]]
I've tried:
function remove(arr, val) {
arr.forEach(v => {
var index = v.indexOf(val);
if (index === -1) {
v.splice(index, 1);
}
});
};
n.forEach(val=>{
remove(m, val);
})
console.log(m)
But i faild....
Is there a solution to solve the problem??
If you're OK with a new array, you can map and filter m by whether the item being iterated over is included in n:
var m = [["a", "b"], ["c", "d", "e"], ["f", "g", "h"]]
var n = ["a","d","e", "h"]
const filteredM = m.map(
arr => arr.filter(
item => n.includes(item)
)
);
console.log(filteredM);
You could iterate from the end of the array and splice not common items.
It is necessary to start from the end, because splice (in this case) changes the length of the array and the actual index, if iterating from start.
var m = [["a", "b"], ["c", "d", "e"], ["f", "g", "h"]],
n = ["a", "d", "e", "h"];
m.forEach(a => {
var i = a.length;
while (i--) {
if (!n.includes(a[i])) {
a.splice(i, 1);
}
}
});
console.log(m); // [["a"], ["d", "e"], ["h"]]
.as-console-wrapper { max-height: 100% !important; top: 0; }
var m = [["a", "b"], ["c", "d", "e"], ["f", "g", "h"]];
var n = ["a","d","e", "h"];
const newarr = m.map(val => val.filter(element => n.includes(element)));
console.log(newarr);

Categories

Resources