Check if every id has an existing object in array - javascript

I would like to check if there is an existing object for every id of an array.
const ids = [ 'xxnQt5X8pfbcJMn6i', 'fbcJMn6ixxnQt5X8p' ]
const target = [
{ _id: 'xxnQt5X8pfbcJMn6i' },
{ _id: 'Qt5X8pfbcJMn6ixxn' },
]
In this example I would like to get false, as the second ID (fbcJMn6ixxnQt5X8p) is not existing.
This should return true:
const ids = [ 'xxnQt5X8pfbcJMn6i', 'fbcJMn6ixxnQt5X8p' ]
const target = [
{ _id: 'xxnQt5X8pfbcJMn6i' },
{ _id: 'Qt5X8pfbcJMn6ixxn' },
{ _id: 'fbcJMn6ixxnQt5X8p' },
]
This is what I've tried:
ids.every(id => target.find(element => element._id === id))

You're pretty close, you need to pass a function instead of an object to find though - and I'd recommend to use some() instead of find if you only want to know about if it exists, rather than you need the object in return.
const ids = [ 'xxnQt5X8pfbcJMn6i', 'fbcJMn6ixxnQt5X8p' ]
const target = [
{ _id: 'xxnQt5X8pfbcJMn6i' },
{ _id: 'Qt5X8pfbcJMn6ixxn' },
{ _id: 'fbcJMn6ixxnQt5X8p' },
]
const allIn = ids.every(id => target.some(({_id}) => id === _id));
console.log(allIn);

With a lot of entries, it might be faster to use a Set (so we get O(n + m) instead of O(n * m)) :
const idSet = new Set(target.map(el => el._id));
const result = ids.every(id => idSet.has(id));

Since every is itself a checker method it's return true or false through the provided function. So you can simply return false:
const res = const res = ids.every(id => target._id === id);
console.log(res);
or true:
const res = ids.every(id => target._id !== id);
console.log(res);

Related

Combine Array Of Strings With String

I need to combine the LAST fromAddress and toAddresses values into just one set of array without duplication and without the loginUser.
Expected Output
{ "newResponse": ["james#gmail.com", "ken#yahoo.com"] }
const loginUser = "jane#gmail.com"
const old = [
{
"toAddresses": ["joker#gmail.com", "jake#gmail.com"],
},
{
"fromAddress": "ken#yahoo.com",
"toAddresses": ["jane#gmail.com", "james#gmail.com"],
}
];
let emailLength = old?.length - 1
let email = old[emailLength]
const newResponse = Array.from(new Set([...email.map(x => [...x.toAddresses].concat([...x.fromAddress || []]))]))
console.log(newResponse)
const loginUser = "jane#gmail.com"
const old = [
{
"toAddresses": ["joker#gmail.com", "jake#gmail.com"],
},
{
"fromAddress": "ken#yahoo.com",
"toAddresses": ["jane#gmail.com", "james#gmail.com"],
}
];
let last = old[old.length - 1];
let combined = new Set([last.fromAddress, ...last.toAddresses]);
combined.delete(loginUser);
let newResponse = Array.from(combined);
console.log({newResponse});
You're trying to call map on an object, but is only an array method.
You can just access the properties directly on the email object, since you know what you're looking for you don't need to iterate on it.
Then filter the array for the logged in user and construct a new object for the response.
const loginUser = "jane#gmail.com"
const old = [
{
"toAddresses": ["joker#gmail.com", "jake#gmail.com"],
},
{
"fromAddress": "ken#yahoo.com",
"toAddresses": ["jane#gmail.com", "james#gmail.com"],
}
];
let emailLength = old?.length - 1
let email = old[emailLength]
let addresses = Array.from(new Set([...email.toAddresses, email.fromAddress]))
addresses = addresses.filter(addy => addy !== loginUser)
const newResponse = { "newResponse": addresses }
console.log(newResponse)

Comparing two array of objects and getting the difference

Hi I'm trying to show a loader for each input field, but only when they have entered a value. The behaviour i'm getting is if i enter a value into one of the text inputs the spinner shows for all. I need to determine my loading state based on the difference of the two arrays, by the array key.
Similar to this post -> How to get the difference between two arrays of objects in JavaScript
const [isLoading, setIsLoading] = useState('');
// before any value has been entered
const initialFormData = [{key: 'USER_DEFINED_QUESTIONS', value: ''}, {key: 'RECOMMENDED_FIELDS', value: ''}]
// when a value has been entered
const values = [{key: 'USER_DEFINED_QUESTIONS', value: 'test'}, {key: 'RECOMMENDED_FIELDS', value: ''}]
const saveSubmit = async (values) => {
const arrValues = Object.entries(values).map((val) => ({
field: val[0],
value: val[1],
}));
const arrInitialFormValues = Object.entries(initialFormData).map(
(val) => ({
field: val[0],
value: val[1],
}),
);
const result = arrValues.filter(
(o1) => !arrInitialFormValues.some((o2) => o1.key === o2.key),
);
const body = { ...values };
setIsLoading(result);
const res = await putResults({ id, body });
if (res && !(await checkErrors(res))) {
return res;
}
setIsLoading(result);
}
return null;
};
You can combine the renaming and filter
const saveSubmit = async (values) => {
const result = initialFormData.reduce((acc, a) => {
const diff = values.find((b) => a.key === b.key && a.value !== b.value)
return diff
? [
...acc,
{
field: diff.key,
value: diff.value,
},
]
: acc
}, [])
const body = { ...values }
setIsLoading(result)
const res = await putResults({ id, body })
if (res && !(await checkErrors(res))) {
return res
}
setIsLoading(result)
}
First of all, I would map the array into an object (this is not needed, it just feels cleaner this way).
values = Object.fromEntries(a.map(entry => [entry.key, entry.value]))
Then I believe, all you really need is to find all entries that have non-negative "value" (if that is not the case, please comment below and I will correct this answer).
usedFields = Object.entries(values).filter(entry => entry[1])
If you want only to get the difference, and that is what i can read from question title, shouldn't this work?
const initialFormData = [{key: 'USER_DEFINED_QUESTIONS', value: ''}, {key: 'RECOMMENDED_FIELDS', value: ''}];
// when a value has been entered
const values = [{key: 'USER_DEFINED_QUESTIONS', value: 'test'}, {key: 'RECOMMENDED_FIELDS', value: ''}];
const keysWhichDiffer = values.map(x => initialFormData.find(y=> x.key===y.key && x.value!==y.value)?.key);
const result = keysWhichDiffer.filter(x=>x);
console.log('res', result)

How to turn array of objects in unique array?

This is my initial data:
const data = [
{
"user":{
"amount":"1",
"date":"2020-07-31T18:34:48.635Z",
"shiftSelected":"10:00"
}
},
{
"user":{
"name":"Name",
"surname":"aaa",
"obs":"eee"
}
}
]
I'm trying to turn an array of objects in unique array. This is my output:
const newData = {
amount: "1",
date: "2020-07-31T18:34:48.635Z",
shiftSelected: "10:00",
name: "Name",
surname:"aaa",
obs:"eee"
}
I can iterate over the array with a map call: let b = data.map(item => item.user), but I need to write more code to join then. I know that it's possible to do it with one unique logic. I tried but without successful.
You can use reduce with Object.assign to merge the properties of the objects. Note that with this method, later properties will overwrite previous ones.
const data = [
{
"user":{
"amount":"1",
"date":"2020-07-31T18:34:48.635Z",
"shiftSelected":"10:00"
}
},
{
"user":{
"name":"Name",
"surname":"aaa",
"obs":"eee"
}
}
];
const result = data.reduce((acc,{user})=>Object.assign(acc,user), {});
console.log(result);
Object spread syntax will also work.
const data = [
{
"user":{
"amount":"1",
"date":"2020-07-31T18:34:48.635Z",
"shiftSelected":"10:00"
}
},
{
"user":{
"name":"Name",
"surname":"aaa",
"obs":"eee"
}
}
];
const result = data.reduce((acc,{user})=>({...acc, ...user}), {});
console.log(result);
const data = [
{
"user":{
"amount":"1",
"date":"2020-07-31T18:34:48.635Z",
"shiftSelected":"10:00"
}
},
{
"user":{
"name":"Name",
"surname":"aaa",
"obs":"eee"
}
}
]
let b = data.reduce((acc, rec) => {
const { user } = rec
return { ...acc, ...user}
}, {} )
console.log(b)
use this after map over datas this is not a logic but.....
const x = data.map(obj => obj.user);
function flatObj(arr) {
const res = {};
arr.forEach(y => {
for(const key in y) {
res[key] = y[key];
}
})
return res;
}
const resault = flatObj(x);

JavaScript Filter return on react app delete all object with the same id

i try to return all object the !== from the object that i deleted now and the filter delete all object with the same name that i clicked.
In my application it is possible to have several identical objects and I want that at the moment of deletion it will be deleted only 1.
here the code
handleClick = packageID => {
let array = [];
packageMethods
.deletePackageFromUser(packageID, this.props.userID)
.then(res => {
packageMethods.findPackage(packageID).then(temppackage => {
array = this.state.package.filter(item => {
return item._id !== temppackage.data[0]._id;
});
this.setState({
package:array
})
});
});
};
You want to find the index of the first instance of an object with that id, then remove the item at that index.
handleClick = packageID => {
let array = [...this.state.package];
packageMethods
.deletePackageFromUser(packageID, this.props.userID)
.then(res => {
packageMethods.findPackage(packageID).then(temppackage => {
const removal_index = array.findIndex(item => {
return item._id === temppackage.data[0]._id;
});
array.splice(removal_index, 1);
this.setState({
package: array
})
});
});
};
Here's an example
const arr = [{id: 1, val: 'a'}, {id: 1, val: 'a'}, {id: 2, val: 'b'}];
console.log(arr);
const removal_index = arr.findIndex(el => el.id == 1); // find index of first object with id of 1
arr.splice(removal_index,1); // remove 1 element starting at `removal_index`
console.log(arr);

Get object in array that contains closest matching id property in a string?

I am wondering if there is a better way to do get the result.
I have an array of objects, each object contains an id as a string path pattern. I want to return the object that has the best match to a url path. ATM I am using lodash
All id's are unique.
const url = '/economia/finanzas/moodys-coloca-calificaciones-de-riesgo-de-costa/JZF24QAQHBBFPLJQL5VZJPKCZA/story/'
const sites = [{
'_id': '/la-nacion/economia'
}, {
'_id': '/la-nacion'
}, {
'_id': '/la-nacion/economia/finanzas'
}, {
'_id': '/la-nacion/economia/moodys'
}]
const urlArr = url.split('/')
const compare = sites.map(site => {
// get all matches
const siteArr = site._id.split('/')
// get lengths of matches
return _.intersection(siteArr, urlArr).length
})
// get index of obj with best match
const indexOfBestMatch = _.indexOf(compare, _.max(compare))
// new primary section
const newPrimarySection = sites.filter((e, i) => {
return i === indexOfBestMatch
})
console.log(newPrimarySection)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
https://jsbin.com/lumepereyi/1/edit?js,console
No need for a library, you can use reduce to iterate over the array of _ids, keeping a count of the number of substring matches, so that it resolves to the one with the most matches:
const url = '/economia/finanzas/moodys-coloca-calificaciones-de-riesgo-de-costa/JZF24QAQHBBFPLJQL5VZJPKCZA/story/';
const sites = [{
'_id': '/la-nacion/economia'
}, {
'_id': '/la-nacion'
}, {
'_id': '/la-nacion/economia/finanzas'
}, {
'_id': '/la-nacion/economia/moodys'
}];
const substrings = new Set(url.split('/'));
const countMatches = str => str.split('/').reduce((a, substr) => a + (substrings.has(substr)), 0);
const { bestMatch } = sites.reduce(({ bestMatch, count=0 }, { _id }) => {
const thisCount = countMatches(_id);
return thisCount > count
? { count: thisCount, bestMatch: _id }
: { count, bestMatch };
}, {});
console.log(bestMatch);
Since you only need the item with the max matches, you can use _.maxBy() to iterate the array of sites, and extract the item. Use _.get() to extract the value of _id, because _.get() won't throw an error if sites is empty:
const url = '/economia/finanzas/moodys-coloca-calificaciones-de-riesgo-de-costa/JZF24QAQHBBFPLJQL5VZJPKCZA/story/'
const sites = [{"_id":"/la-nacion/economia"},{"_id":"/la-nacion"},{"_id":"/la-nacion/economia/finanzas"},{"_id":"/la-nacion/economia/moodys"}]
const getPrimarySection = (url, sites) => {
const urlArr = url.split('/')
return _.get(_.maxBy(sites, site => {
const siteArr = site._id.split('/')
return _.intersection(siteArr, urlArr).length
}), '_id')
}
const newPrimarySection = getPrimarySection(url, sites)
console.log(newPrimarySection)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
If your path prefix is always the same (like it seems it is with /la-naction then you could do your own scoring (via startsWith) based on the length of the matched string and then sort-by desc (biggest score) ... and take the top score:
const url = '/economia/finanzas/moodys-coloca-calificaciones-de-riesgo-de-costa/JZF24QAQHBBFPLJQL5VZJPKCZA/story/'
const sites = [{"_id":"/la-nacion/economia"},{"_id":"/la-nacion"},{"_id":"/la-nacion/economia/finanzas"},{"_id":"/la-nacion/economia/moodys"}]
const getBestMatch = (s, u, p = '/la-nacion') => { // <-- default prefix
const topScored = s.map(x =>
(Object.assign(x, {
score: ((`${p}${u}`).startsWith(x._id) ? x._id.length : 0)}), x)
).sort((a, b) => b.score - a.score)[0] // <-- sort, get the highest score
return topScored.score > 0 ? topScored._id : undefined
}
console.log(getBestMatch(sites, url))
No lodash neeed etc it is just map to add the score and then sort really.

Categories

Resources