Javascript find and count duplicate key values - javascript

I have a JSON array as follows:
var testJSON = [
{ "AssetA": "asset_a", "AssetB": "asset_b" },
{ "AssetA": "asset_a", "AssetB": "asset_b" },
{ "AssetA": "asset_c", "AssetB": "asset_d" },
{ "AssetA": "asset_c", "AssetB": "asset_e" }];
What I'd like to do is count all the duplicates. For example, I'd like my result to be another array, where the first two elements of the row are are the repeating values, and the third element is the number of times it repeats like so:
[{asset_a, asset_b,2},
{asset_c, asset_d,1},
{asset_c, asset_e,1}]
Here is what I have so far to be able to identify the duplicates, but it keeps getting hung up and my visual studio crashes:
for (var i = 0; i < testJSON.length; i++) {
for (var j = i + 1; j < testJSON.length;) {
if (testJSON[i][0] == testJSON[j][0] && testJSON[i][1] == testJSON[j][1])
// Found the same. Remove it.
console.log("they are equal");
else
// No match. Go ahead.
j++;
}
}

You could use an object for collecting and an array for the result set
Both properties are used as key and used for lookup in the array. If not found, the a new array is build with the needed values and inserted into the result set. Then the count gets increased.
var testJSON = [{ "AssetA": "asset_a", "AssetB": "asset_b" }, { "AssetA": "asset_a", "AssetB": "asset_b" }, { "AssetA": "asset_c", "AssetB": "asset_d" }, { "AssetA": "asset_c", "AssetB": "asset_e" }],
result = [];
testJSON.forEach(function (a) {
var k = a.AssetA + '|' + a.AssetB;
if (!this[k]) {
this[k] = [a.AssetA, a.AssetB, 0];
result.push(this[k]);
}
this[k][2]++;
}, Object.create(null));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

testJSON[i][0]
I do not believe this will work like that. What you have is an ARRAY of OBJECTS.
Therefore, testJSON[i] will return an OBJECT, not an ARRAY, therefore testJSON[i][0] shouldn't return anything valuable. What you want is testJSON[i]['AssetA']
Hangup
Another thing is when if (testJSON[i][0] == testJSON[j][0] && testJSON[i][1] == testJSON[j][1]) succeds on j = i+1. In this case, you will just keep iterating on the same value of j. You need to add j++ to your forloop and delete the else clause, or handle it otherwise for desired effect.
For example
for (var i = 0; i < testJSON.length; i++) {
for (var j = i + 1; j < testJSON.length; j++) {
if (testJSON[i]["AssetA"] == testJSON[j]["AssetA"] &&
testJSON[i]["AssetB"] == testJSON[j]["AssetB"])
console.log("they are equal");
}
}

Related

How to ignore the loop in else case

I have to compare two values. Both values came from different loops.
if the value is an exact match, I push the array differently.
As you can see in the code. I cant use an "else" after the "if" function because it will literate till the loop stop. I would have multiple pushes.
If I add the array.push after the loop there will be 2 pushes.
for (var prop in obj) {
var array = []
for (var item in obj[prop]) {
for (var i = 0; i < doctyp88.length; i += 1) {
var doctyp88ID = doctyp88[i]._id;
var doctyp88name = doctyp88[i]._source['88_name'];
if (item == doctyp88ID) {
array.push({
"name": item,
"count": obj[prop][item],
"archivname": doctyp88name,
});
}
}
array.push({
"name": item,
"count": obj[prop][item],
});
}
}
What is the best way to avoid my problem?
for (var prop in obj) {
var array = []
for (var item in obj[prop]) {
const newObj = {
"name": item,
}
for (var i = 0; i < doctyp88.length; i += 1) {
var doctyp88ID = doctyp88[i]._id;
var doctyp88name = doctyp88[i]._source['88_name'];
newObj.count= obj[prop][item],
if (item == doctyp88ID) {
newObj.archivname = doctyp88name
}
}
array.push(newObj);
}
}
If I understood your question correctly you could use break [label]; statement to exit from nested loop and skip more pushes but don't exit outside for like this:
loop_1:
for (var prop in obj) {
var array = []
loop_2:
for (var item in obj[prop]) {
loop_3:
for (var i = 0; i < doctyp88.length; i += 1) {
var doctyp88ID = doctyp88[i]._id;
var doctyp88name = doctyp88[i]._source['88_name'];
if (item == doctyp88ID) {
array.push({
"name": item,
"count": obj[prop][item],
"archivname": doctyp88name,
});
break loop_2;
}
}
array.push({
"name": item,
"count": obj[prop][item],
});
}
}

JavaScript: transform a string to json with some rules

I need to write a function which can transform the following data (input string) to a json.
data:
AA,BB
,CC
,,DD
,EE
JSON:
{
"AA": [
{
"BB": []
},
{
"CC": [
{
"DD": []
}
]
},
{
"EE": []
}
]
}
AA, BB, CC ... can any string and the data is input as a string.
I write a part of the function (see the following codes) and have no more good idea.
function str2json(str) {
var lines = str.split("\n");
var arr = new Array();
for (let i = 0; i < lines.length; i++)
{
var objs = lines[i].split(",");
arr.push(objs);
}
for (let i=0; i < arr.length; i++)
{
for (let j=0; j < arr[i].length; j++)
{
if(arr[i][j].length === 0)
{
arr[i][j] = arr[i-1][j];
}
else
{
break;
}
}
}
// TODO
}
I just transform the data into an array then add right data into null, the result is:
AA,BB
AA,CC
AA,CC,EE
AA,FF
Then I thought of using a loop to create an object then use JSON.stringify(object).
How can I continue or redo it?
Thanks!
You could take a helper array for all last levels and pick the result from the first element.
This works because you take after splitting an empty string as flag for taking the last array for inserting a new object.
var data = 'AA,BB\n,CC\n,,DD\n,EE',
result = [],
levels = [result];
data
.split('\n')
.forEach(s => s
.split(',')
.forEach((v, i) => {
if (!v) return;
levels[i].push({ [v]: (levels[i + 1] = []) });
})
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

I keep getting cannot read property error

I am trying to do a bubblesort. I am using this algorithm to sort a 2d array and I keep getting an error. Here is the function:
var array = [
[ "Rober Hill" , 123.54 ],
[ "Chrsitopher Reddkin", 54.67 ],
[ "Maggie Woods" , 1000.87 ],
[ "Jennifer Jones" , 3.34 ],
[ "Marcus Parker" , 64.98 ]
];
table = document.getElementById("table");
function bubbleSort(array, length, element)
{
var swapped = false;
do
{
for (var a = 0; a < 5; a++) // Line 59
{
if (array[a][1] > array[a+1][1])
{
var temp = array[a][1];
array[a][1] = array[a+1][1];
array[a+1][1] = temp;
swapped = true;
}
}
} while(swapped);
return array;
}
The error says: Sorting.html:59 Uncaught TypeError: Cannot read property '0' of undefined. I have this function on a button. Any kind of help would be nice! Thank you
Running your code exactly as it is, I get:
Cannot read property '1' of undefined
This is because in your comparison, you're attempting to compare array[a][1] > array[a+1][1], and this works except for the last loop, where array[a+1] doesn't exist, and because it doesn't exist, 1 is undefined.
Here's a working solution, with a few notable differences.
I don't know why you had length, and element as parameters for your bubbleSort, but they're gone now
You can just use the array length in your for loop, that way if you add more items to your array, you don't have to update the 5 you had hardcoded.
In the for loop, I minus 1 from the array length so we're never trying to compare the last item against an item after it that doesn't exist.
Also, I used i instead of a, since that's a common variable name for an incrementer.
I defined swapped inside the do...while, otherwise you'll have created an infinite loop because swapped will get set to true on the first pass and stay true forever.
You don't have to return the array, as it is modifying the original in place when you call bubbleSort
var array = [
["Rober Hill", 123.54],
["Chrsitopher Reddkin", 54.67],
["Maggie Woods", 1000.87],
["Jennifer Jones", 3.34],
["Marcus Parker", 64.98]
];
function bubbleSort(array) {
do {
var swapped = false;
for (var i = 0; i < array.length - 1; i++) {
if (array[i][1] > array[i + 1][1]) {
var temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
swapped = true;
}
}
} while (swapped);
}
bubbleSort(array)
console.log(array);
Move var swapped = false; inside do {....
Also update condition in for it should be like a < 4; or it's better if you use generalized condition as a < array.length - 1;
var array = [
["Rober Hill", 123.54],
["Chrsitopher Reddkin", 54.67],
["Maggie Woods", 1000.87],
["Jennifer Jones", 3.34],
["Marcus Parker", 64.98]
];
function bubbleSort(array, length, element) {
do {
var swapped = false;
for (var a = 0; a < array.length - 1; a++) // Line 59
{
if (array[a][1] > array[a + 1][1]) {
var temp = array[a][1];
array[a][1] = array[a + 1][1];
array[a + 1][1] = temp;
swapped = true;
}
}
} while (swapped);
return array;
}
console.log(bubbleSort(array));

Compare string to array of object

I come up with this solution to compare a string to an array of object. However, I don't think this is the best solution. Any suggestion on how to make this function perform better for large array of object?
var a = "blAh";
var b = [{
"tag": "tag1",
"icons": ["blah"]
}, {
"tag": "tag2",
"icons": ["Blah", "apple", "banana", "bLaH"]
}];
// Desired output "tag1, tag2"
function getTitle(tags, icon) {
let arr = [];
for (var i = 0; i < tags.length; i++) {
tags[i].icons.forEach(elem => {
if (icon.toLowerCase() === elem.toLowerCase()) {
if (!arr.includes(tags[i].tag)) {
arr.push(tags[i].tag);
}
}
});
}
return arr.join(', ');
}
console.log(getTitle(b, a));
for readability, I would use the following :
var res = b.filter(el =>
el.icons.length < 0
? false
: el.icons.map(icon => icon.toLowerCase()).indexOf(a.toLocaleLowerCase()) != -1
).map(el => el.tag).join(', ');
But for performances, this one would be better :
var res = [];
var i, j;
for (i = 0; i < b.length; i++) {
if (b[i].icons.length < 0) {
} else {
for (j = 0; j < b[i].icons.length; j++)
b[i].icons[j] = b[i].icons[j].toLowerCase();
if (b[i].icons.indexOf(a.toLocaleLowerCase()) !== -1)
res.push(b[i].tag);
}
}
res = res.join(', ');
Here is why :
indexOf is always faster than includes (or equal in old versions of chrome). benchmark
for loops are always faster than array methods like filter, map or reduce. benchmarks : map, filter
Also it's intresting to see that for loops are faster than indexOf in the latest version of chrome (60)
Hope it helps,
Best regards

JavaScript looping through an array to check for numeric values

I have an an array that returns the values such as the following:
//Eg 1 [ [ "214323", "34243" ], [ "3333", "123" ] ]
//Eg 2 [ [ "214323" ],[ "3333" ] ]
I want to validate if the array holds only numbers with no spaces or null, else I would like to throw an error.
This is my following code and it does not work in the above example. It throws out an error even though all values are numeric.
for (var i = 0; i <= arrayVals.length; i++) {
if(!(/^\d+$/.test(arrayVals[i]))) {
err_comp=true;
}
}
if( err_comp ==true) {
alert( 'The value has to be only numeric.');
}
You have an array of arrays, thus you need two loops:
var err_comp = false;
for (var i = 0; i < arrayVals.length; i++) {
var arr = arrayVals[i];
for (var j = 0; j < arr.length; j++) {
if (!(/^\d+$/.test(arr[j]))) {
err_comp = true;
}
}
}
Otherwise, you'd be testing /^\d+$/.test([ "214323", "34243" ]).
you should not use <= because you start with 0 you should use <:
for (var i = 0; i < arrayVals.length;
multi_arr.every(function(arr) {
return arr.every(function(n) {
return /^\d+$/.test(n);
});
});
You can change the test as you need, and you can add a .every patch for IE8 if you want.
And you can make reusable your functions.
function forEveryArray(fn) {
return function every_array(arr) {
return arr.every(fn)
}
}
function isNumber(n) { return /^\d+$/.test(n); }
multi_arr.every(forEveryArray(isNumber));

Categories

Resources