Remove objects from array where an attribute is equal to specific string - javascript

I am using an array.filter() function to remove all the objects where one of their attribute is equal to any of the string in a given array.
The objects in the array are crypto trades and I need to filter out the trades with the trade pairs that I do not want. How would I achieve this using the filter function?
For now, I tried this which did not work evidently:
filteredPairs = filteredPairs.filter(
(pair) =>
!pair.symbol.includes(
"USDTBUSD",
"USDTUSDC",
"USDTUST",
"USDTUSDP",
"USDTDAI",
"BUSDUSDT",
"BUSDUSDC",
"BUSDUST",
"BUSDUSDP",
"BUSDDAI",
"USDCUSDT",
"USDCBUSD",
"USDCUST",
"USDCUSDP",
"USDCDAI",
"USTUSDT",
"USTBUSD",
"USTUSDC",
"USTUSDP",
"USTDAI",
"USDPUSDT",
"USDPBUSD",
"USDPUSDC",
"USDPUST",
"USDPDAI",
"DAIUSDT",
"DAIBUSD",
"DAIUSDC",
"DAIUSDP",
"DATUST"
)
);
This is not filtering out these pairs. Any insight would be helpful. Thank you.

This can be done in a single line.
// testing object
const filteredPairs = [
{
symbol: 'USDTBUSD',
},
{
symbol: 'abc',
},
{
symbol: 'BUSDUSDT',
},
{
symbol: '321',
},
];
// items we don't want
const blacklist = [
'USDTBUSD',
'USDTUSDC',
'USDTUST',
'USDTUSDP',
'USDTDAI',
'BUSDUSDT',
'BUSDUSDC',
'BUSDUST',
'BUSDUSDP',
'BUSDDAI',
'USDCUSDT',
'USDCBUSD',
'USDCUST',
'USDCUSDP',
'USDCDAI',
'USTUSDT',
'USTBUSD',
'USTUSDC',
'USTUSDP',
'USTDAI',
'USDPUSDT',
'USDPBUSD',
'USDPUSDC',
'USDPUST',
'USDPDAI',
'DAIUSDT',
'DAIBUSD',
'DAIUSDC',
'DAIUSDP',
'DATUST',
];
// filter
const newFilteredPairs = filteredPairs.filter(({ symbol }) => !blacklist.some((item) => symbol.includes(item)));
console.log(newFilteredPairs);

Related

From single array convert to an array of object with keys coming from a JSON response -JAVASCRIPT-

I am receiving a json response from an API call. I need to store its keys, and create an array of an object. I am intending to this array of an object is created dynamically no matter the keys of the response.
I've already got the keys like this:
const json_getAllKeys = data => {
const keys = data.reduce((keys, obj) => (
keys.concat(Object.keys(obj).filter(key => (
keys.indexOf(key) === -1))
)
), [])
return keys
}
That returned an array (using a sample json):
['name','username', 'email']
But I am trying to use that array to create an array of object that looks like this one
[
{
name: "name",
username: "username",
email: "Email",
}
];
I've been trying mapping the array, but got multiple objects because of the loop, and I need a single one to make it work.
keys.map(i=>({i:i}))
[
{ i: 'id' },
{ i: 'name' },
{ i: 'username' },
{ i: 'email' }
]
Any hint would be useful!
Thanks in advance :D
What you're looking for is Object.fromEntries, which is ECMA2019, I believe, so available in Node >=14 and will be provided as a polyfill if you employ babel.
I can't quite discern what your reduce should produce, but given the sample input, I would write
const input = ['name','username', 'email'];
const result = Object.fromEntries(input.map(name => ([name, name])));
// result == { name: 'name', username: 'username', email: 'email' }
You're definitely on the right track. One thing to remember is the map function will return the SAME number of output as input. So in your example, an array of 3 returns an array of 3 items.
For this reason, map alone is not going to give you what you want. You may be able to map => reduce it. However, here is a way using forEach instead. This isn't a strictly functional programming style solution, but is pretty straight forward and depending on use case, probably good enough.
let keys = ['name','username', 'email'] //you have this array
const obj = {}; // empty object to hold result
keys.forEach(i => {
obj[i] = i; // set the object as you want
})
console.log(obj); // log out the mutated object
// { name: 'name', username: 'username', email: 'email' }

How can I filter through an array of objects based on a key in a nested array of objects?

I am having a hard time filtering through an array of objects based on a value in a nested array of objects. I have a chat application where a component renders a list of chats that a user has. I want to be able to filter through the chats by name when a user types into an input element.
Here is an example of the array or initial state :
const chats= [
{
id: "1",
isGroupChat: true,
users: [
{
id: "123",
name: "Billy Bob",
verified: false
},
{
id: "456",
name: "Superman",
verified: true
}
]
},
{
id: "2",
isGroupChat: true,
users: [
{
id: "193",
name: "Johhny Dang",
verified: false
},
{
id: "496",
name: "Batman",
verified: true
}
]
}
];
I want to be able to search by the Users names, and if the name exists in one of the objects (chats) have the whole object returned.
Here is what I have tried with no results
const handleSearch = (e) => {
const filtered = chats.map((chat) =>
chat.users.filter((user) => user.name.includes(e.target.value))
);
console.log(filtered);
// prints an empty array on every key press
};
const handleSearch = (e) => {
const filtered = chats.filter((chat) =>
chat.users.filter((user) => user.name.includes(e.target.value))
);
console.log(filtered);
// prints both objects (chats) on every keypress
};
Expected Results
If the input value is "bat" I would expect the chat with Id of 2 to be returned
[{
id: "2",
isGroupChat: true,
users: [
{
id: "193",
name: "Johhny Dang",
verified: false
},
{
id: "496",
name: "Batman",
verified: true
}
]
}]
The second approach seems a little closer to what you're trying to accomplish. There's two problems you may still need to tackle:
Is the search within the name case insensitive? If not, you're not handling that.
The function being used by a filter call needs to return a boolean value. Your outer filter is returning all results due to the inner filter returning the array itself and not a boolean expression. Javascript is converting it to a "truthy" result.
The following code should correct both of those issues:
const filtered = chats.filter((chat) => {
const searchValue = e.target.value.toLowerCase();
return chat.users.filter((user) => user.name.toLowerCase().includes(searchValue)).length > 0;
});
The toLowerCase() calls can be removed if you want case sensitivity. The .length > 0 verifies that the inner filter found at least one user with the substring and therefore returns the entire chat objects in the outer filter call.
If you want to get object id 2 when entering bat you should transform to lowercase
const handleSearch = (e) =>
chats.filter(chat =>
chat.users.filter(user => user.name.toLowerCase().includes(e.target.value)).length
);
try this it should work
const handleSearch2 = (e) => {
const filtered = chats.filter((chat) =>
chat.users.some((user) => user.name.includes(e))
);
console.log(filtered);
};
filter needs a predicate as argument, or, in other words, a function that returns a boolean; here some returns a boolean.
Using map as first iteration is wrong because map creates an array with the same number of elements of the array that's been applied to.
Going the easy route, you can do this.
It will loop first over all the chats and then in every chat it will check to see if the one of the users' username contains the username passed to the function. If so, the chat will be added to the filtered list.
Note, I am using toLowerCase() in order to make the search non case sensitive, you can remove it to make it case sensitive.
const handleSearch = (username) => {
var filtered = [];
chats.forEach((chat) => {
chat.users.forEach((user) => {
if (user.name.toLowerCase().includes(username.toLowerCase())) {
filtered.push(chat);
}
});
});
console.log(filtered);
return filtered;
}
handleSearch('bat');

Match array value with value in an array of objects javascript

I am trying to work out how I can return a list with values from the own key in the array bellow if the object name value matches values in the lookupvalues array
lookupvalues = ["ross","linda"]
resources = [{own: "car", name: "bob"},{own: "bike", name: "ross"},{own: "plane", name: "linda"}]
wanted_output = ["bike","plane"]
I am struggling a bit with a good method to use for when I need to compare value in an object with array values. Is there a reasonable straight forward way to do this?
I must say how impressed I am that I got 4 replies with working examples at the same time!
One way (array method chaining) is that you could filter by name and map to grap each's own
const lookupvalues = ["ross", "linda"]
const resources = [
{ own: "car", name: "bob" },
{ own: "bike", name: "ross" },
{ own: "plane", name: "linda" },
]
const res = resources
.filter(({ name }) => lookupvalues.includes(name))
.map(({ own }) => own)
console.log(res)
resources.filter(resource => lookupvalues.includes(resource.name))
.map(resource => resource.own);
This will filter by the items that have names that are included in lookupvalues, and then transform the array into an array of the own values of those remaining.
You can take the help of Array#filter and Array#map:
const lookupvalues = ["ross","linda"]
const resources = [{own: "car", name: "bob"},{own: "bike", name: "ross"},{own: "plane", name: "linda"}]
const filterRes = (arr) => {
const lookup = new Set(lookupvalues);
return arr.filter(({name}) => lookup.has(name))
.map(({own}) => own);
}
console.log(filterRes(resources));
resources.filter(item => lookupvalues.indexOf(item.name) > -1).map(item => item.own)

Filter array of objects based on the input passed: Javascript

I have an array of objects with the following structure
arr = [ { name: "abc" , items: ["itemA","itemB","itemC"], days :138} ,
{ name: "def" , items: ["itemA1","itemB2","itemC1"], days :157} ,
{ name: "hfg" , items: ["itemAN","itemB7","itemC7"], days :189} ]
This array needs to be filtered based on the search input passed. I was able to achieve the same for the name , where days is not getting filtered.
Also can someone help how to search across items array too so it filters the rows based on input passed
This is what I have tried
handleSearch = (arr, searchInput) => {
let filteredData= arr.filter(value => {
return (
value.name.toLowerCase().includes(searchInput.toLowerCase()) ||
value.days.toString().includes(searchInput.toString())
);
});
console.log(filteredData);
//this.setState({ list: filteredData });
}
You can use Array#some and then perform the same kind of match that you've already done :
The some() method tests whether at least one element in the array passes the test implemented by the provided function. It returns a Boolean value.
handleSearch = (arr, searchInput) => {
const filteredData = arr.filter(value => {
const searchStr = searchInput.toLowerCase();
const nameMatches = value.name.toLowerCase().includes(searchStr);
const daysMatches = value.days.toString().includes(searchStr);
const oneItemMatches = value.items.some(item => item.toLowerCase().includes(searchStr));
return nameMatches || daysMatches || oneItemMatches;
});
console.log(filteredData);
//this.setState({ list: filteredData });
}
As your search value can apply to all fields in your data array, you can combine the values together in one array (row by row) and perform the search in one place.
To do that, I've provided a snippet below that will filter the original array checking each object's values after the transformations. These involve using Object.values() to get the values of the object in an array, since this array is nested, we can make use of Array.flat() to flatten it into just the strings and numbers, finally call Array.some() to check if one of the values partially includes the search value (after they've both been lowercase-d).
const arr = [
{ name: "abc" , items: ["itemA","itemB","itemC"], days: 138 },
{ name: "def" , items: ["itemA1","itemB2","itemC1"], days: 157 },
{ name: "hfg" , items: ["itemAN","itemB7","itemC7"], days: 189 }
];
const handleSearch = (arr, searchInput) => (
arr.filter((obj) => (
Object.values(obj)
.flat()
.some((v) => (
`${v}`.toLowerCase().includes(`${searchInput}`.toLowerCase())
))
))
);
console.log('"A1" =>', JSON.stringify(handleSearch(arr, 'A1')));
console.log('189 =>', JSON.stringify(handleSearch(arr, 189)));
console.log('"nope" =>', JSON.stringify(handleSearch(arr, 'nope')));
NOTE: This approach has one obvious flaw, it will seach through numbers as strings, meaning that providing 89 as the search value will still return the second element.

In Reselect selector augment object with keyed objects if object key exist in another array

Trying to learn a concept.
If I have Object of keyed objects and an array of keys.
const orders = {
"key1" : { id: "key1", number: "ORD001" },
"key3" : { id: "key3", number: "ORD003" },
"key2" : { id: "key2", number: "ORD002" },
};
and an array:
const selectedOrders = ["key1","key2"];
and with the help of Redux Reselect. I want to have a new object like:
const orders = {
"key1" : { id: "key1", number: "ORD001" selected: true},
"key3" : { id: "key3", number: "ORD003" selected: false },
"key2" : { id: "key2", number: "ORD002" selected: true },
};
So later I can iterate over that object via Object.keys(this.orders) and style selected items.
Is this correct to use Reselect for such use-case? If yes, then how should I check-in an efficient and idiomatic way, does an external array contains a given key?
If this idea is totally wrong for such use-case, then how should I do that in the right way?
Addendum: There also could be another array which contains keys in sequence how those orders should be displayed. (User is able to reorder items).
P.S. I don't want to use an array of objects for orders collection.
Yes, you can use reselect to combine two sets of data to produce a third set. Due to reselect's memoization, if the inputs don't change, then the calculation only needs to be performed once.
// You'll need some input selectors to pluck the raw orders from your redux store.
// I'm making these up, since i don't know how your store is arranged.
const getOrders = (state) => state.orders;
const getSelectedOrders = (state) => state.selectedOrders;
const getAugmentedOrders = createSelector(
[getOrders, getSelectedOrders],
(orders, selectedOrders) => {
const augmentedOrders = {};
Object.keys(orders).forEach(key => {
augmentedOrders[key] = {
...orders[key],
selected: selectedOrders.includes(key),
}
});
return augmentedOrders;
}
);
If you have a lot of selected orders, then doing selectedOrders.includes every time through the loop may be a performance problem. In that case i'd create a Set of the selectedOrders, since lookups into the Set will be constant time.
(orders, selectedOrders) => {
const selectedSet = new Set(selectedOrders);
const augmentedOrders = {};
Object.keys(orders).forEach(key => {
augmentedOrders[key] = {
...orders[key],
selected: selectedSet.has(key),
}
});
return augmentedOrders;
}

Categories

Resources