I have an array address like so
[
{
id: "83",
country: "China",
type: "NORMAL"
},
{
id: "84",
country: "California",
type: "HOME"
},
{
id: "85",
country: "Brazil",
type: "NORMAL"
},
{
id: "86",
country: "India",
type: "WORK"
},
]
How I move two items with type is HOME and WORK to the front of array like so: HOME first then come WORK then another.
[
{
id: "84",
country: "California",
type: "HOME"
},
{
id: "86",
country: "India",
type: "WORK"
},
{
id: "83",
country: "China",
type: "NORMAL"
},
{
id: "85",
country: "Brazil",
type: "NORMAL"
},
]
Thank you :))
I think you can use JS array sort method, I provide you an example below (pseudo code):
const order = ['HOME', 'WORK', 'NORMAL'];
const arr = [{id: "83", country: "China", type: "NORMAL"}, {...}] // your array to sort
const sorted = arr.sort((a, b) => order.indexOf(a.type) > order.indexOf(b.type));
Related
I use fuse.js with useExtendedSearch enabled. I have an array of objects. Each of the objects has a key of type array that contains objects.
I want to search for values in both the outer array and the inner array. It works if the search keyword is in the outer array. But it does not work, if the inner array contains the search keyword.
In the code below, I want to filter the countries such that it contains only the object whose name is exactly as the search keyword.
const data = [{
"continent": "Asia",
countries: [{
name: "Korea"
},
{
name: "Japan"
},
{
name: "China"
},
{
name: "Pakistan"
},
]
},
{
"continent": "Europe",
countries: [{
name: "Albania"
},
{
name: "France"
},
{
name: "England"
},
{
name: "Spain"
},
]
},
{
"continent": "Africa",
countries: [{
name: "Algeria"
},
{
name: "Angola"
},
{
name: "Benin"
},
{
name: "South Africa"
},
]
}
]
const options = {
useExtendedSearch: true,
keys: [
"continent",
"countries.name"
]
};
const fuse = new Fuse(data, options);
// Change the pattern
const pattern = "=Pakistan"
console.log(fuse.search(pattern))
<script src="https://cdn.jsdelivr.net/npm/fuse.js#6.6.2"></script>
But it only filters the outer array.
[{
"continent": "Asia",
countries: [{
name: "Korea"
},
{
name: "Japan"
},
{
name: "China"
},
{
name: "Pakistan"
},
]
}]
I expect it to retun:
[{
"continent": "Asia",
countries: [{
name: "Pakistan"
}]
}]
Is it possible to achive this in Fuse.js?
I have an array of objects that I would like to filter but I do not know the properties that I have in the objects (neither the data nor the filter array):
myArray = [
{ id: "100", area: "01", country: "AT"},
{ id: "101", area: "02", country: "DE"},
{ id: "102", area: "01", country: "DE"},
{ id: "103", area: "03", country: "CH"},
{ id: "104", area: "01", country: "AT"}
]
and my filter is:
myFilter = { area: "01", country: "AT" }
I would like to have this returned:
myArrayFiltered = [
{ id: "100", area: "01", country: "AT"},
{ id: "104", area: "01", country: "AT"}
]
How would I go about doing this? Just to be perfectly clear, I do not know the properties that I will be searching for i.e. I do not know which properties myArray or myFilter will have. If the filter contains a key that is not in myArray I would expect an empty array!
PS: I do also not know how many entries are going to be filters by i.e. depending what my users enter I could just get:
myFilter = [ {area: "01"} ]
myArray.filter((item) =>
Object.entries(myFilter).every(([key, val]) => item[key] === val))
var myArray =
[
{ id: "100", area: "01", country: "AT"},
{ id: "101", area: "02", country: "DE"},
{ id: "102", area: "01", country: "DE"},
{ id: "103", area: "03", country: "CH"},
{ id: "104", area: "01", country: "AT"}
]
var myFilter = { area: "01", country: "AT" }
var filteredArray = myArray.filter(function(item) {
return Object.keys(myFilter).every(function(c) {
return item[c] === myFilter[c];
});
} );
console.log(filteredArray)
myArray.filter((item) => Object.keys(item).every((key) => !myFilter[key]|| myFilter[key] === item[key]))
I am working on a side project where I am comparing two different databases and want to find the common elements of the data sets based on the "id" field. I want to know if there is an optimal solution instead of using two nested for loops. Is there a way to do it with a hash map? Many Thanks!
Below is the sample code I am working with.
UPDATE all ids are unique with no possibility of there being a duplicate
// data set 1
const set1 = [
{
id: "001",
name: "bob",
age: "50",
location: "texas"
},
{
id: "002",
name: "bill",
age: "51",
location: "texas"
},
{
id: "003",
name: "ben",
age: "52",
location: "texas"
},
{
id: "004",
name: "cam",
age: "53",
location: "texas"
},
{
id: "005",
name: "max",
age: "54",
location: "texas"
}
]
// data set 2
const set2 = [
{
id: "001",
name: "bob"
},
{
id: "002",
name: "bill"
}
]
// I want to create a function where I find the the common elements of the two lists based on id and put the common element of data set 1 into a list and return that list
const findUnion(set1, set2) {
// logic here, I know I can do a nested for loop but is there a more efficient way such as
// using a hashmap? ( Map() object? )
}
// desired output
const output = [
{
id: "001",
name: "bob",
age: "50",
location: "texas"
},
{
id: "002",
name: "bill",
age: "51",
location: "texas"
}
]
You can use Sets for efficient lookup:
const ids1 = new Set(set1.map(({id}) => id));
const ids2 = new Set(set2.map(({id}) => id));
const output = set1.filter(({id}) => ids1.has(id) && ids2.has(id));
console.log(output);
First of all, you're looking for the intersection, not the union.
As others have said, we can use a Set to track uniqueness. This gives us near O(1) lookup time, and allows us algorithm that runs in something like O(m + n) time where m and n are the sizes of your sets:
const intersection = (s1, s2, ids = new Set (s2 .map (x => x .id))) =>
s1 .filter (({id}) => ids .has (id))
const set1 = [{id: "001", name: "bob", age: "50", location: "texas"}, {id: "002", name: "bill", age: "51", location: "texas"}, {id: "003", name: "ben", age: "52", location: "texas"}, {id: "004", name: "cam", age: "53", location: "texas"}, {id: "005", name: "max", age: "54", location: "texas"}]
const set2 = [{id: "001", name: "bob"}, {id: "002", name: "bill"}]
console .log (intersection (set1, set2))
.as-console-wrapper {max-height: 100% !important; top: 0}
First we combine into one long array. Then group by id using reduce method. Each group contains the item and count of appearances. Finally, for each of the groups, return only those with count of appearances > 1.
Edit: fixed algorithm see code.
Edit 2: Made it more generic so order of items won't matter. This is by extending the duplicates rather then replacing them.
function findUnion(set1, set2) {
// first remove duplicates from each set
// bonus: collect duplicates
var duplicates;
function dedup(set) {
duplicates = []
return Object.values(set.reduce(function(agg, item) {
var merged = item;
if (agg[item.id]) {
merged = { ...agg[item.id],
...item
}
duplicates.push(merged)
}
agg[item.id] = merged;
return agg
}, {}));
}
set1 = dedup(set1);
set2 = dedup(set2);
// then combine
var combined = [...set1, ...set2]
// then remove duplicates again, this time keep them
dedup(combined)
return duplicates;
}
// data set 1
const set1 = [{
id: "001",
name: "bob",
age: "50",
location: "texas"
},
{
id: "002",
name: "bill",
age: "51",
location: "texas"
},
{
id: "003",
name: "ben",
age: "52",
location: "texas"
},
{
id: "004",
name: "cam",
age: "53",
location: "texas"
},
{
id: "005",
name: "max",
age: "54",
location: "texas"
},
{
id: "005",
name: "max",
age: "54",
location: "texas"
},
{
id: "005",
name: "max",
age: "54",
location: "texas"
}
]
// data set 2
const set2 = [{
id: "001",
name: "bob"
},
{
id: "002",
name: "bill"
}
]
// desired output
const output = [{
id: "001",
name: "bob",
age: "50",
location: "texas"
},
{
id: "002",
name: "bill",
age: "51",
location: "texas"
}
]
console.log(findUnion(set1, set2))
Below is the data that I am receiving and I am trying to filter so that a new array contains only objects with the desired location.
However, I'm running into an issue where my function is returning [], an empty array.
data:
[
{ data: [[Object], [Object], [Object]], id: 1 },
{ data: [[Object]], id: 2 },
{ data: [[Object], [Object], [Object], [Object]], id: 3 }
];
data[1]:
{"data": [{"name": "Joe", "job": "N/A", "location": "Los Angeles"}], "id": 2}
This is my current function:
const locations = ["Los Angeles", "Chicago"];
...
const filteredData = data.filter((i) =>
i.data.filter((j) => locations.includes(j.location)),
);
return filteredData;
What is wrong and how can I fix this and get it filtering correctly?
In the callback you pass to the Array.filter(), you need to return a boolean value to filter the array. If you do not return anything, the filter returns an empty array.
But in your case, you are returning inner filtered array that returns at least an empty array and the outer filter behaves it as a true value. So the outer filter will return all of the items in the original array. (not an empty one as you stated)
Also you are returning filteredData in a place where it results in a syntax error.
const data = [
{"data": [{"name": "Joe", "job": "N/A", "location": "Los Angeles"}], "id": 2},
{"data": [{"name": "Jane", "job": "N/A", "location": "Charlotte"}], "id": 3},
]
const locations = ["Los Angeles", "Chicago"];
const filteredData = data.filter((i) =>
i.data.filter((j) => locations.includes(j.location)).length > 0,
);
console.log(filteredData);
Another Option is use some() to get your expected result. This way you don't need to loop through all item in data array comparing to filter()
const data = [
{ data: [{ name: "Joe", job: "N/A", location: "Los Angeles" }], id: 2 },
{ data: [{ name: "Jane", job: "N/A", location: "Charlotte" }], id: 3 },
{ data: [{ name: "Sam", job: "N/A", location: "SSS" }], id: 4 },
{
data: [
{ name: "John", job: "N/A", location: "AAA" },
{ name: "Doe", job: "N/A", location: "BBB" },
],
id: 5,
},
];
const locations = ["Los Angeles", "Chicago", "AAA"];
const existData = data.filter(el =>
el.data.some(item => locations.includes(item.location))
);
console.log(existData);
If you also want to filter the data array, you can do like below.
const data = [
{ data: [{ name: "Joe", job: "N/A", location: "Los Angeles" }], id: 2 },
{ data: [{ name: "Jane", job: "N/A", location: "Charlotte" }], id: 3 },
{ data: [{ name: "Sam", job: "N/A", location: "SSS" }], id: 4 },
{
data: [
{ name: "John", job: "N/A", location: "AAA" },
{ name: "Doe", job: "N/A", location: "BBB" },
],
id: 5,
},
];
const locations = ["Los Angeles", "Chicago", "AAA"];
const filteredData = data.reduce((acc, cur) => {
const filteredItem = cur.data.filter(item => locations.includes(item.location));
if (filteredItem.length) {
acc.push({ ...cur, data: filteredItem });
}
return acc;
}, []);
console.log(filteredData);
var trees = [
{
name: "alex",
lastname: "watson",
city: "California",
state: "Alameda",
childrens: [
{ name: "shane watson", city: "Troy", state: "Alabama" },
{
name: "adam watson",
city: "Palmer",
state: "Alaska",
childrens: [
{ name: "ana watson", city: "Avondale", state: "Arizona" },
{ name: "ama watson", city: "Douglas", state: "Arizona" }
]
}
]
},
{
name: "adam",
lastname: "ronaldo",
city: "Bradenton",
state: "Florida",
childrens: [
{ name: "austin ronaldo", city: "Alhambra", state: "California" },
{
name: "kira ronaldo",
city: "Calexico",
state: "California",
childrens: [
{ name: "sam ronaldo", city: "Chico", state: "California" },
{
name: "godwin ronaldo",
city: "Eureka",
state: "California",
childrens: [
{ name: "michael ronaldo", city: "Buffalo", state: "New York" }
]
}
]
}
]
}
];
Find out city in JSON array variable trees (eg. city = "Buffalo" or name = "Godwin ronaldo")
delete found nodes from parent tree variable.
this function gives matching nodes:
function findMatchingNodes(nodes, predicate) {
const results = [];
function walk(node) {
if (predicate(node)) {
results.push(node);
}
(node.childrens || []).forEach(walk);
}
nodes.forEach(walk);
return results;
}
Function calling
const matches = findMatchingNode(
trees,
(n) => n.city === 'Buffalo' || n.name === 'godwin ronaldo'
);
I want to delete the matching node.
matches.forEach(node => {
delete node;
});
output: SyntaxError: Deleting local variable in strict mode
https://jsfiddle.net/5sve3nxc/
Working fiddle to push trees child node. I want to delete node instead of pushing.
While you need to splice the array, if the predicate is true, you need to iterate from the end of the array, to maintain the index.
function deleteFromArray(array, predicate) {
var i = array.length;
while (i--) {
if (predicate(array[i])) {
array.splice(i, 1);
continue;
}
if (array[i].children) {
deleteFromArray(array[i].children, predicate);
}
}
}
var tree = [{ name: "alex", lastname: "watson", city: "California", state: "Alameda", children: [{ name: "shane watson", city: "Troy", state: "Alabama" }, { name: "adam watson", city: "Palmer", state: "Alaska", children: [{ name: "ana watson", city: "Avondale", state: "Arizona" }, { name: "ama watson", city: "Douglas", state: "Arizona" }] }] }, { name: "adam", lastname: "ronaldo", city: "Bradenton", state: "Florida", children: [{ name: "austin ronaldo", city: "Alhambra", state: "California" }, { name: "kira ronaldo", city: "Calexico", state: "California", children: [{ name: "sam ronaldo", city: "Chico", state: "California" }, { name: "godwin ronaldo", city: "Eureka", state: "California", children: [{ name: "michael ronaldo", city: "Buffalo", state: "New York" }] }] }] }];
deleteFromArray(tree, ({ city, name }) => city === 'Buffalo' || name === 'godwin ronaldo');
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }