I have two immutable map:
const first_map = Map({a: 1, b: 2)}
const second_map = Map({a: 1, b: 3)}
How to get the difference?
I should get:
Map({b: 3})
One possible approach is using Map.filter() - which is actually Collection.Keyed.filter() - on the second map with one condition: for a given element of this Map, there should be no element in another Map with the same key. For example:
const Map = Immutable.Map;
const first_map = Map({a: 1, b: 2, c: 4});
const second_map = Map({a: 1, b: 3, d: 5});
const diff = second_map.filter((v, k) => first_map.get(k) !== v);
console.log(diff.toString()); // Map { "b": 3, "d": 5 }
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.2/immutable.min.js"></script>
Strictly speaking, one should check for has first - as Map.get(key) returns undefined if there's no such key, but there might be valid cases for Map containing undefined. Still, I'd encourage using null for such values.
Related
This question already has answers here:
Update javascript object with another object, but only existing keys
(6 answers)
Closed 10 months ago.
How to achive this result :
const defaultValues = { a:1, b:1 , c:1};// All acceptable properties
const overrideValues = { a:2, x: 3, y: 3, z:3 };// from user
const values = ? ;//
console.log(values);
// output:
// Object { a: 2, b: 1, c: 1 }
Thxs,
Post-Edit :
Thank you all for your precious help.
(I read the duplicate question: Update javascript object with another object, but only existing keys)
However, I still offer you my solution :
const overrideValues = { a:2, x: 3, y: 3, z:3 };
const defaultValues = {
a: overrideValues.a || 1,
b: overrideValues.b || 1,
c: overrideValues.c || 1
};
const values = defaultValues ;// !
console.log(values);
// output:
// Object { a: 2, b: 1, c: 1 }
You can map over the entries of the default values and set the value to the value in overrideValues for each key that exists on that object.
const defaultValues = { a:1, b:1 , c:1};
const overrideValues = { a:2, x: 3, y: 3, z:3 };
const values = Object.fromEntries(Object.entries(defaultValues)
.map(([k,v])=>[k, overrideValues.hasOwnProperty(k) ? overrideValues[k] : v]));
console.log(values);
You can use spread syntax:
const defaultValues = { a:1, b:1 , c:1};// All acceptable values
const overrideValues = { a:2, x: 3, y: 3, z:3 };
const values = {...defaultValues, ...overrideValues};
console.log(values);
Spread syntax allows you to destructure an object or array, and you can use that restructuring to have default values. If there are multiple instances of a key/value pair, then the second value seen for that key is used, allowing you to override the defaults.
I have the following object
const d = {
a: 1,
b: 2,
c: 3,
}
What a I want to do is something like this:
const type = R.ifElse(R.isEmpty(R.prop('a')), "company", "personal")(d)
The equivalent in pure javascript would be
const type = d.a ? "personal" : "company"
How can I do this with ramda?
(Disclaimer: I have literally no experience with Ramda.js, I just looked it up and tried out a little bit. There may be a better solution)
You can use R.always instead of the strings, as it expects functions there. For checking if the object has a property you can use R.has
const d = {
a: 1,
b: 2,
c: 3,
}
const x = R.ifElse(R.has('a'), R.always("company"), R.always("personal"))(d)
This question already has answers here:
JavaScript get elements from an object array that are not in another
(5 answers)
Closed 3 years ago.
I want an array that contains objects from the scrape object that are not present in the old object. The arrays I'm actually working with contains nearly 100 objects.
The code below works, but I wonder if there's a more efficient way of getting the same result?
var old = [
{a: 6, b: 3},
{a: 1, b: 1},
{a: 3, b: 3}
]
var scrape = [
{a: 1, b: 1},
{a: 5, b:5}
]
var nogood = []
var good =[]
scrape.forEach(es => {
old.forEach(e => {
if(e.a == es.a) {
nogood.push(es)
}
})
})
console.log(nogood)
nogood.forEach(main =>
good = scrape.filter(e=> e.a!=main.a)
)
console.log(good)
This is what I expect and what I'm getting:
good = {a:5, b:5}
Personally I would approach this with:
const old = [
{a: 6, b: 3},
{a: 1, b: 1},
{a: 3, b: 3}
];
const scrape = [{a: 1, b: 1}, {a: 5, b:5}];
for (const item of old) {
for (const i in scrape) {
if (JSON.stringify(item) === JSON.stringify(scrape[i])) {
scrape.splice(i, 1); //delete the previously scraped item
}
}
}
console.log(scrape); //{a: 5, b:5}
The benefits to this approach are:
You don't care what properties the objects you're comparing have,
you just care about whether they're identical.
It's fast
(comparing JSON is generally faster than traversing the objects to
compare each property).
It's more succinct to splice the scrape
array rather than adding the 'good' and 'nogood' arrays to arrive at
a filtered scrape array.
Possible deal breaker is if the objects you're comparing contain methods, in which case comparing them via JSON is not the correct approach.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
If we have arrays old and scrape to be of size M and N, respectively, all traditional approaches has the complexity of O(M * N) because you need to compare each entry within array scrape with the ones exists in array old to find out whether matches or not.
The second and more efficient approach is to create a hash table on first array, typically on bigger one (old here), and iterate over the second one (scrape here) which has the complexity of O(M + N).
If the size of M and N be as big as enough, the differences show themselves. As an example if M=100 and N=200, the former one needs to compare 20000 objects but the later one needs just 300 comparisons.
please take a look at this code:
const old = [
{a: 6, b: 3},
{a: 1, b: 1},
{a: 3, b: 3}
]
const scrape = [
{a: 1, b: 1},
{a: 5, b:5}
]
// create hash map using built-in Javascript Map
const pair = old.map(x => [JSON.stringify(x), true])
const map = new Map(pair)
// filter those object does not exist in hash map
const good = scrape.filter(x => !map.has(JSON.stringify(x)))
console.log(good)
How about something like this?
const good = scrape.filter((sEl) => {
return !old.some(oEl => oEl.a === sEl.a);
})
This avoids the nested forEach loops and .some will return as soon as a single true condition is found, avoiding some excess searching when an element exists early in the 'old' array.
May be something like:
var old = [
{a: 6, b: 3},
{a: 1, b: 1},
{a: 3, b: 3}
]
var scrape = [
{a: 1, b: 1},
{a: 5, b:5}
]
var result = scrape.filter(s => old.findIndex(o => o.a === s.a) === -1);
console.log(result);
This question already has answers here:
Javascript | Unique object in Set
(2 answers)
Closed 4 years ago.
I have a logic that accepts a configuration and returns a value. However, I'd like to retrieve from the cache for the further tries of same configuration. The order of keys may be varied within the config but must be treated as the same configuration.
Comments explain what I try to achieve. I expect only two openings as there are only two different config in the sample code. Only first and second attempts of open() goes as expected because of the same object passing to the map as a key.
If I try to keep the keys as a JSON string then the order of the keys can be problematic.
Here is what I have tried so far. I appreciate any idea or alternative solution.
var m = new Map();
function opening(config) {
// ...
return "foo";
}
function open(config = {}) {
if (!m.has(config)) {
m.set(config, opening(config));
console.log("open and set: ", config);
} else {
console.log("get from the map: ", config);
}
return m.get(config);
}
var c1 = { a: 1, b: 2 };
open(c1); // open and set [OK]
open(c1); // get from the map [OK]
open({ a: 1, b: 2 }); // get from the map
open({ b: 2, a: 1 }); // get from the map, even in different orders
open({ a: 1, b: 2, c: 3 }); // open and set
open({ a: 1, c: 3, b: 2 }); // get from the map
It looks like you need a way to represent the different objects such that identical key-value pairs (in different orders) can be recognized as the same key in the map. One option would be to take the object and sort its entries according to the keys' alphabetical order, and then stringify the sorted entries:
var m = new Map();
function opening(config) {
// ...
return "foo";
}
function open(config = {}) {
const key = objToKeyValStr(config);
if (!m.has(key)) {
m.set(key, opening(config));
console.log("open and set: ", config);
} else {
console.log("get from the map: ", config);
}
return m.get(config);
}
function replacer(_, value) {
if (typeof value !== 'object' || Array.isArray(value)) return value;
return objToKeyValStr(value);
}
const objToKeyValStr = obj => (
JSON.stringify(
Object.entries(obj).sort((a, b) => a[0].localeCompare(b[0])),
replacer
)
);
var c1 = { a: 1, b: 2 };
open(c1); // open and set [OK]
open(c1); // get from the map [OK]
open({ a: 1, b: 2 }); // get from the map
open({ b: 2, a: 1 }); // get from the map, even in different orders
open({ a: 1, b: 2, c: 3 }); // open and set
open({ a: 1, c: 3, b: 2 }); // get from the map
open({ a: 1, b: { c: 1, d: 1 }}); // open and set
open({ a: 1, b: { d: 1, c: 1 }}); // get from the map
I'd like to find best practice for getting the same section of two objects
const firstObject = { a: 1, b: 2, c: 3}
const secondObject = { 1, 2 }
// desired result: { a: 1, b: 2} or simply { a, b }
In my opinion, we need to do three steps:
1) Get value all values of each object
Object.values = Object.values || (obj => Object.keys(obj).map(key => obj[key]))
2) Find the same section from two arrays value
3) Find key-value pair from firstObject
Any other ways to do it?
Using Standard built-in objects as Array or Object is preferable
Break the firstObject into [key, value] pairs using Object#entries (or polyfill), and use Array#reduce to combine all those that exist in the secondObject.
const firstObject = { a: 1, b: 2, c: 3}
const secondObject = { 1: 1, 2: 2 };
const result = Object.entries(firstObject).reduce((obj, [key, value]) => {
value in secondObject && (obj[key] = value);
return obj;
}, {})
console.log(result);
Object.keys(firstObject).filter(key=> key in secondObject).reduce((o,k)=>(o[k]=firstObject[k],o),{});