I don't know how this is possible i want to print array which contain same value and difference value.
I want to check if the value is present in both the array if present then print it in one array which contain all the same value of both array and another array which contain name which is difference.
readFileArray:
[
[
mainFolder/abc_doc.txt,
mainFolder/pqr_doc.txt,
mainFolder/subFolder/xyz_image.jpg,
mainFolder/subFolder/iop_pdf.pdf,
],
[
Fish,
Life,
Qwerty,
Moon
]
]
comparePathName:
[
mainFolder/abc_doc.txt,
mainFolder/pqr_doc.txt,
mainFolder/subFolder/xyz_image.jpg,
mainFolder/subFolder/iop_pdf.pdf,
mainFolder/fish.txt,
mainFolder/life.txt,
mainFolder/subFolder/qwerty.jpg,
mainFolder/subFolder/moon.pdf,
]
code:
for (let i = 0; i <= readFileArray.length - 1; i++) {
for (let j = 0; j < readFileArray[i].length - 1; j++) {
if (readFileArray[i][j] === comparePathName) {
availableName = readFileArray[1][j];
if (typeof availableName !== undefined) {
console.log(availableName)
}
}
}
}
output:
the value which are present in both the array i am getting it in availableName
availableName=
[
mainFolder/abc_doc.txt,
mainFolder/pqr_doc.txt,
mainFolder/subFolder/xyz_image.jpg,
mainFolder/subFolder/iop_pdf.pdf,
]
Now I also need the non-similar value in my new array which name is expectedArray
expectedArray=
[
mainFolder/fish.txt,
mainFolder/life.txt,
mainFolder/subFolder/qwerty.jpg,
mainFolder/subFolder/moon.pdf,
]
We can create functions to get the intersection and difference of the two arrays as below, then we call them by passing the relevant values.
I've decided to use Set.has rather than Array.includes to improve performance (though this would only make a difference for very large arrays)
const readFileArray = [ [ 'mainFolder/abc_doc.txt', 'mainFolder/pqr_doc.txt', 'mainFolder/subFolder/xyz_image.jpg', 'mainFolder/subFolder/iop_pdf.pdf', ], [ 'Fish', 'Life', 'Qwerty', 'Moon' ] ]
const comparePathName = [ 'mainFolder/abc_doc.txt', 'mainFolder/pqr_doc.txt', 'mainFolder/subFolder/xyz_image.jpg', 'mainFolder/subFolder/iop_pdf.pdf', 'mainFolder/fish.txt', 'mainFolder/life.txt', 'mainFolder/subFolder/qwerty.jpg', 'mainFolder/subFolder/moon.pdf', ]
/* Return all the items in one array only, use sets to avoid N squared behaviour */
function getSymmetricDifference(array1, array2) {
const set1 = new Set(array1);
const set2 = new Set(array2);
const itemsInArray1Only = array1.filter(el => !set2.has(el))
const itemsInArray2Only = array2.filter(el => !set1.has(el))
return itemsInArray1Only.concat(itemsInArray2Only)
}
/* Return all common items, use set to avoid N squared behaviour */
function getIntersection(array1, array2) {
const set2 = new Set(array2);
return array1.filter(el => set2.has(el));
}
console.log("Intersection:", getIntersection(readFileArray[0], comparePathName))
console.log("Difference:", getSymmetricDifference(readFileArray[0], comparePathName))
One simple way to do it is using array.filter and includes methods:
To get the common values, filter will iterate the first array and includes will check the second array for the current value. To get the difference, check if the current value is not found in the second array.
let availableName = readFileArray[0].filter(value => comparePathName.includes(value))
let expectedArray = comparePathName.filter(value => !readFileArray[0].includes(value))
Of course, to get all different values you will need to filter both ways by switching the arrays in the code above, and then combine the results. Or simply check which array's got more elements and use that for the filter.
Simple example:
let readFileArray = [
[
'mainFolder/abc_doc.txt',
'mainFolder/pqr_doc.txt',
'mainFolder/subFolder/xyz_image.jpg',
'mainFolder/subFolder/iop_pdf.pdf',
],
[
'Fish',
'Life',
'Qwerty',
'Moon'
]
]
let comparePathName = [
'mainFolder/abc_doc.txt',
'mainFolder/pqr_doc.txt',
'mainFolder/subFolder/xyz_image.jpg',
'mainFolder/subFolder/iop_pdf.pdf',
'mainFolder/fish.txt',
'mainFolder/life.txt',
'mainFolder/subFolder/qwerty.jpg',
'mainFolder/subFolder/moon.pdf',
]
let availableName = readFileArray[0].filter(value => comparePathName.includes(value))
let expectedArray = comparePathName.filter(value => !readFileArray[0].includes(value))
console.log('Common', availableName)
console.log('Different', expectedArray)
Related
I want to return true if the number 2 is contained in this array of arrays. How can I do this using javascript? This is an example of my array of arrays:
[
[1, "Canteen" ],
[2, "Swift Room"]
]
I have been trying something like the following:
const isBooked = slotsForDate.map((val) => {
if (val.includes(slot.id)) {
return true;
}
});
But I have had no luck yet.
You can try using Array.prototype.some() like the following way:
const slotsForDate = [
[
1,
"Canteen"
],
[
2,
"Swift Room"
]
]
const isBooked = slotsForDate.some(val => val.includes(2));
console.log(isBooked);
Another way would be to flatten the nested array with Array.flat(), then call Array.includes() on the return. Probably the shortest code:
const isBooked = slotsForDate.flat().includes(slot.id);
Here's a brute force approach to help you understand the logic.
const checkArr = (check) => {
for(let i=0; i<arr.length; i++){
for(let j=0; j<arr[i].length; j++){
if(arr[i][j] === check){
//return true here
console.log(arr[i][j]);
}
}
}
//return false here
}
let arr = [
[
1,
"Canteen"
],
[
2,
"Swift Room"
]
]
let checkValue = 2;
checkArr(checkValue);
This recursive function works for nested arrays no matter how many levels of arrays there are. It goes through each item of an array and check if target is there:
const ar = [[1,"Canteen"],
[2,"Swift Room"]];
function searchElement(a, target, index = 0) {
if (index >= a.length)
return false;
return (Array.isArray(a[index]) ? searchElement(a[index], target) :
a[index] === target)
|| searchElement(a, target, index + 1);
}
console.log(
searchElement(ar, 2)
);
Despite my other answer being marked as accepted, I think the way the problem is stated may not be the safest way.
If that were my code, I would investigate just the first item of each array that forms the inner elements of the main/outer array. Because I only want to match the slot identifier, not a slot description that may be the same as (some other slot's) identifier.
I would do that via something like:
const slotID = 2;
const isBooked = slotsForDate.some(slot => slot[0] === slotId);
In general IMHO, data structure design is probably as important as algorithm design, the more so now that the programming world (including JavaScript) moves toward a Functional Programming paradigm. In this endeavour it helps to be clear (and state clearly when communicating with others) what the different parts of a data structure mean, and to state problems (even if to yourself) in the more abstract meaning ("I want to see if a slot exists with the given ID") instead of the more concrete implementation details ("Is there a 2 somewhere in the data structure?"). Then when implementing the solution, it should reflect the abstract intention, which will cause less unintended bugs and better readability/understandability to a later maintainer.
Further musings:
A data structure that would capture the intent of the system better would be something like the below. Although one can not always argue with what is supplied by legacy or third-party components...
const slotsForDate = [
{id: 1, desc: 'Canteen'},
{id: 2, desc: 'Swift room'}
]
The following should also be possible (taking the JS object convention to implicitly state the key/id and the value/description:
const slotsForDate = {
1: 'Canteen',
2: 'Swift room'
}
which then translates to a (sparse) array - provided the ID is strictly numeric, it can now be implicitly used as the array index:
const slotsForDate = [ undefined, 'Canteen', 'Swift room' ]
Where checking if a slot is booked is as simple as:
const slotID = 2;
const isBooked = !!slotsForDate[slotId];
const slotsForDate = [
[
1,
"Canteen"
],
[
2,
"Swift Room"
]
];
function check(n){
let find = false;
slotsForDate.forEach(element => {
if (element[0] === n){
find = true;
}
});
return find;
}
console.log(check(2));
Problem
I would like to have the below two JSON combined together using the ID and have the expected result as mentioned below. I have tried a few solutions that were available but none worked for my use case. Any suggestions will be great !!
Tried to do:
How to merge two json object values by id with plain Javascript (ES6)
Code
var json1 = [
{
"id":"A123",
"cost":"5020.67",
"fruitName":"grapes"
},
{
"id":"A456",
"cost":"341.30",
"fruitName":"apple"
},
{
"id":"A789",
"cost":"3423.04",
"fruitName":"banana"
}
];
var json2 = [
{
"id":"A123",
"quantity":"7"
},
{
"id":"A789",
"quantity":"10"
},
{
"id":"ABCD",
"quantity":"22"
}
];
Below is the code I tried:
var finalResult = [...[json1, json2].reduce((m, a) => (a.forEach(o => m.has(o.id) && Object.assign(m.get(o.id), o) || m.set(o.id, o)), m), new Map).values()];
Expected result:
[
{
"id":"A123",
"cost":"5020.67",
"fruitName":"grapes",
"quantity":"7"
},
{
"id":"A456",
"cost":"341.30",
"fruitName":"apple"
},
{
"id":"A789",
"cost":"3423.04",
"fruitName":"banana",
"quantity":"10"
},
{
"id":"ABCD",
"quantity":"22"
}
]
You can accomplish this fairly easily without getting too fancy. Here's the algorithm:
Put the items from json1 into an object by id, so that you can look them up quickly.
For each item in json2: If it already exists, merge it with the existing item. Else, add it to objectsById.
Convert objectsById back to an array. I've used Object.values, but you can also do this easily with a loop.
var json1 = [
{
"id":"A123",
"cost":"5020.67",
"fruitName":"grapes"
}, {
"id":"A456",
"cost":"341.30",
"fruitName":"apple"
}, {
"id":"A789",
"cost":"3423.04",
"fruitName":"banana"
}
];
var json2 = [
{
"id":"A123",
"quantity":"7"
}, {
"id":"A789",
"quantity":"10"
}
];
const objectsById = {};
// Store json1 objects by id.
for (const obj1 of json1) {
objectsById[obj1.id] = obj1;
}
for (const obj2 of json2) {
const id = obj2.id;
if (objectsById[id]) {
// Object already exists, need to merge.
// Using lodash's merge because it works for deep properties, unlike object.assign.
objectsById[id] = _.merge(objectsById[id], obj2)
} else {
// Object doesn't exist in merged, add it.
objectsById[id] = obj2;
}
}
// All objects have been merged or added. Convert our map to an array.
const mergedArray = Object.values(objectsById);
I think a few steps are being skipped in your reduce function. And it was a little difficult to read because so many steps are being combined in one.
One critical piece that your function does not account for is that when you add 2 numerical strings together, it concats the strings.
const stringTotal = "5020.67" + "3423.04" // result will be "5020.673423.04"
The following functions should give you the result you are looking for.
// calculating the total cost
// default values handles cases where there is no obj in array 2 with the same id as the obj compared in array1
const calcualteStringTotal = (value1 = 0, value2 = 0) => {
const total = parseFloat(value1) + parseFloat(value2)
return `${total}`
}
const calculateTotalById = (array1, array2) => {
const result = []
// looping through initial array
array1.forEach(outterJSON => {
// placeholder json obj - helpful in case we have multiple json in array2 with the same id
let combinedJSON = outterJSON;
// looping through second array
array2.forEach(innerJSON => {
// checking ids
if(innerJSON.id === combinedJSON.id) {
// calls our helper function to calculate cost
const updatedCost = calcualteStringTotal(innerJSON.cost, outterJSON.cost)
// updating other properties
combinedJSON = {
...outterJSON,
...innerJSON,
cost: updatedCost
}
}
})
result.push(combinedJSON)
})
return result
}
const combinedResult = calculateTotalById(json1, json2)
I figured that by using reduce I could make it work.
var finalResult = [...[json1, json2].reduce((m, a) => (a.forEach(o => m.has(o.id) && Object.assign(m.get(o.id), o) || m.set(o.id, o)), m), new Map).values()];
What is the most efficient way to get data out of the following JSON object as two separate arrays?
let dates = [];
let values = [];
For example, I want to get [0] index values from each array and save to a dates Arr, and [1] index values and save to a values Arr.
Is there a way to destructure the object and assign variables to each element? or would a for loop within a forEach() function be the best approach?
Obj {
"data": [
[
"1947-01-01",
243.1
],
[
"1947-04-01",
246.3
],
[
"1947-07-01",
250.1
],
[
"1947-10-01",
260.3
]
}
Note: The JSON object is being retrieved through a fetch API call.
You could use a combination of pre-sized arrays, a single loop, and index-based destructuring. That should be pretty speedy; it prevents array-resizing and spares you from any of the unnecessary per-iteration (or even multi-iteration) processing/logic that comes along with some of the other approaches.
const data = [
[
"1947-01-01",
243.1
],
[
"1947-04-01",
246.3
],
[
"1947-07-01",
250.1
],
[
"1947-10-01",
260.3
]
];
// get data length
let n = data.length;
// initialize output arrays of length n
const dates = new Array(n);
const values = new Array(n);
// loop, decrementing n
while (n--) {
// destructure, assigning at corresponding indices in target arrays
[dates[n],values[n]] = data[n];
}
console.table({dates, values});
<script src="https://gh-canon.github.io/stack-snippet-console/console.min.js"></script><style>.as-console-wrapper{display:block}</style><script>console.config({timeStamps:false,maximize:true})</script>
Since you expressed an interest in efficiency, here's a jsbench test comparing a few of the competing solutions.
I have an array that looks like this:
var myArray = [ "name1+data1" , "name2+data2" , "name3+data3", "name4+data4" ]
When the user enters name1, I would like to open an alert box and display data1, for name2 it should display data2, and so on.
In order to do this, I was wondering how I could split all the strings without using more than one array? And how do I display only data1 when name1 is entered by the user?
I’ve tried using myArray.split("+") but it does not work.
You could map the splitted strings and get an object form the key/value pairs.
var array = ['name1+data1', 'name2+data2', 'name3+data3', 'name4+data4'],
object = Object.fromEntries(array.map(s => s.split('+')));
console.log(object);
You could try implementing below function that takes two arguments.
targetArray is the array to perform search and searchString is the string to search. In your case searchString would be name1. The time complexity is based on the position of the element in the array O(K).
function findMatch(targetArray, searchString) {
const targetElement = targetArray.find(item => {
const leftSplit = item.split('+')[0];
return leftSplit === searchString;
});
if (targetElement) {
return targetElement.split('+')[1];
} else {
return null;
}
}
window.alert(
findMatch([ "name1+data1" , "name2+data2" , "name3+data3", "name4+data4" ], 'name2')
);
Alerts: "data2"
If it is an array, then you need to iterate through the array.
const output = myArray.filter(arrayItem => arrayItem.includes(userInput))[0].split('+')[0];
The time complexity here would be O(N+M), where N is length of array and M is the length of the string.
I think it would be better if myArray is maintained as a dictionary,
const myArray = {
name1: 'data1',
name2: 'data2',
name3: 'data3'
}
const output = myArray[userInput];
The time complexity would be decreased to O(1)
You could use this snippet
var myArray = [ "name1+data1" , "name2+data2" , "name3+data3", "name4+data4" ];
var userValue = prompt('Valeur à rechercher...');
myArray.map((item) => {
if(~item.search(userValue) && userValue.length > 0){
alert(item.split('+')[1]);
return false;
}
})
So, here's an example where name1 and name2 have values, but not the others:
let pairs = [ "name1+data1" , "name2+data2" , "name3+", "name4+" ]
We can split each of those into two-element arrays:
let arr = pairs.map(p=>p.split('+'))
And filter out the ones with empty names:
arr = arr.filter(a=>a[1].length > 0)
arr.join("\n") // "name1,data1
// name2,data2"
Does that do what you want?
I am trying to compare two different arrays together, One previous and one current. The previous set of data contains:
[
{"member_name":"Test1","item":"Sword"},
{"member_name":"Test2","item":"Sword"}
]
The new set contains:
[
{"member_name":"Test1","item":"Sword"},
{"member_name":"Test2","item":"Sword"},
{"member_name":"Test1","item":"Shield"}
]
So as you can see here Test1 has obtained a new item. I've tried to compare these two arrays together a few ways but with no avail.
The methods I've tried:
This one just returns the entire array. Not individual items.
Items_Curr.filter(function(item) { return !Items_Prev.includes(item); });
This method just returns 3 Undefined's.
Items_Curr.map(e => { e.member_name });
I've been looking through trying to find a way of doing this but other posts just explain methods to determine change in simpler arrays.
E.G [a,b] - [a, b, c]
Update:
The end goal is I'd like to create a new array 'NewItems' which would contain an array of all the newly added names and items. So if there is change, I would like that to be broadcasted, if there is no change, then ignore until the function has been ran again.
Realistically you want to do something like:
[a, b, c] - [a, b]
Which would give you c. You can achieve this using .some, which allows you to "customize" the includes functionality.
See example below:
const arr1 = [
{"member_name":"Test1","item":"Sword"},
{"member_name":"Test2","item":"Sword"}
];
const arr2 = [
{"member_name":"Test1","item":"Sword"},
{"member_name":"Test2","item":"Sword"},
{"member_name":"Test1","item":"Shield"}
];
const res = arr2.filter(({member_name:a, item:x}) => !arr1.some(({member_name:b, item:y}) => a === b && x === y));
console.log(res);
If you know your properties will always be in the same order you can use JSON.stringify to serialize the objects and compare the results:
const Items_Prev = [
{"member_name":"Test1","item":"Sword"},
{"member_name":"Test2","item":"Sword"}
]
const Items_Curr = [
{"member_name":"Test1","item":"Sword"},
{"member_name":"Test2","item":"Sword"},
{"member_name":"Test1","item":"Shield"}
]
const serialized_Items_Prev = Items_Prev.map(i => JSON.stringify(i));
const NewItems = Items_Curr.filter(i => !serialized_Items_Prev.includes(JSON.stringify(i)));
console.log(NewItems);
I think something like this you need to do if keys of objects are not changing and new items are only added at last.
const array1 = [
{"member_name":"Test1","item":"Sword"},
{"member_name":"Test2","item":"Sword"}
];
const array2 = [
{"member_name":"Test1","item":"Sword"},
{"member_name":"Test2","item":"Sword"},
{"member_name":"Test1","item":"Shield"}
];
const compare = (array1, array2) => {
if (array1.length !== array2.length) {
return false;
}
for (let i = 0; i < array1.length; i += 1) {
if (array1[i].member_name !== array2[i].member_name) {
return false;
}
if (array1[i].item !== array2[i].item) {
return false;
}
}
return true;
};
console.log(compare(array1, array2));
If order of objects are changing, then you need to write sorting algo for array and then compare.
You can acheieve it using array methods filter() and findIndex()
Filter current array with out put of findIndex() function on previous array
var prevItems = [
{"member_name":"Test1","item":"Sword"},
{"member_name":"Test2","item":"Sword"}
]
var currItems = [
{"member_name":"Test1","item":"Sword"},
{"member_name":"Test2","item":"Sword"},
{"member_name":"Test1","item":"Shield"},
{"member_name":"Test2","item":"Shield"}
]
var newItems = currItems.filter(function(currItem ){
return prevItems.findIndex(function(prevItem){
return prevItem.member_name == currItem.member_name &&
prevItem.item == currItem.item
}) == -1
})
console.log(newItems)