How can i override a map1 with another map2 leaving the key which is not available in the map2 in Dart? - flutter

I am new to flutter/dart, i have to replace a map with another map only when there is key match between them else leave the first map as it is.
This should work like array_replace_recursive() function in PHP.
Here is the code sample:
map1 = {
"t":{
"l":{
"-2":{
"n":"rocky",
"e":"rohit#gmail.com",
"r":"23567"
}
},
"o":{
"xyz":{
"p":"hi",
"x":"cdcbcbk"
}
}
},
"lang":{
"eng":"english",
"spn":"spanish"
}
"sc":{
"math"{
"lb":"30",
"pr":"60"
}
}
}
i have to overide it with
map2 = {
"t":{
"l":{
"-2":{
"n":"rohit",
}
},
},
}
expected output should be
finalMap = {
"t":{
"l":{
"-2":{
"n":"rohit",
"e":"rohit#gmail.com",
"r":"23567"
}
},
"o":{
"xyz":{
"p":"hi",
"x":"cdcbcbk"
}
}
},
"lang":{
"eng":"english",
"spn":"spanish"
}
"sc":{
"math"{
"lb":"30",
"pr":"60"
}
}
}
Thanks

Check this once, made changes based on your specification
replaceIfSame(Map a,Map b){
b.keys.forEach((k){
if(a.containsKey(k)){
if(a[k] is Map && b[k] is Map){
replaceIfSame(a[k],b[k]);
}
else{
a[k] = b[k];
}
}
});
}
Here replaceIfSame is a function that I call recursively passing the maps as input.
Do specify if it's not the case.
Cheers!!

I tried below method it also gives the same result but i'm not sure whether it is efficient or not
Map<dynamic, dynamic> mergemap(Map map1, Map map2) {
map2.forEach((k, v) {
if (map1.containsKey(k)) {
if (v.runtimeType != String) {
mergemap(map1[k], v);
} else {
map1[k] = v;
}
}
});
return map1;
}

Related

What is the use of assert in the following program creating a linked list? Isn't it useless?

bool isTree(List<Object> tree) {
if ((tree is! List) | (tree.length < 1)) {
return false;
}
for (final branch in branches(tree)) {
if (!isTree(branch)) {
return false;
}
}
return true;
}
List branches(List tree) {
return tree.sublist(1);
}
Object label(List tree) {
return tree[0];
}
List tree(rootLabel, [List branches = const []]) {
for (final branch in branches) {
assert(isTree(branch));
}
return ([rootLabel] + branches);
}
bool isLeaf(List tree) {
return branches(tree).isEmpty;
}
var t = tree('hey', [
tree('hello'),
tree('hum', [tree('there'), tree('hey')])
]);
If i were to remove the for loop with the assert function, and also the is_tree function, the program still returns the same results as with them, So aren't they useless?
List branches(List tree) {
return tree.sublist(1);
}
Object label(List tree) {
return tree[0];
}
List tree(rootLabel, [List branches = const []]) {
return ([rootLabel] + branches);
}
bool isLeaf(List tree) {
return branches(tree).isEmpty;
}
var t = tree('hey', [
tree('hello'),
tree('hum', [tree('there'), tree('hey')])
]);
Here is the full tutorial when i am learning this https://composingprograms.com/pages/23-sequences.html#trees
It's there to make sure all branches are trees. Without the assert you are able to write this without any errors.
var t = tree('hey', ['notATree']);
With the assert it will throw an error.

Flutter, bug in classes

In main.dart I call Quiz's function getQuestionText and getQuestionAnswer, getQuestionText works as expected but the other doesn't work, if returns me always the first result of the list. I just placed a debugPrint() and as expected getQuestionText() prints the correct number, getQuestionAnswer() always print 0, how is that possible?
class Quiz {
int _questionNumber = 0;
List<Question> _questions = [
Question('Some cats are actually allergic to humans', true),
Question('You can lead a cow down stairs but not up stairs.', false),
];
void nextQuestion() {
if (_questionNumber < _questions.length - 1) {
_questionNumber++;
}
}
String getQuestionText() {
print('$_questionNumber'); // <-- print the correct number
return _questions[_questionNumber].questionText;
}
bool getQuestionAnswer() {
print('$_questionNumber'); // <-- always print 0
return _questions[_questionNumber].questionAnswer;
}
}
Here how I call the functions
void checkAnswer(bool userAnswer) {
bool correctAnswer = Quiz().getQuestionAnswer();
setState(() {
if (userAnswer == correctAnswer) {
// right answer
} else {
// wrong pick
);
}
quiz.nextQuestion();
});
}
The problem is that you always create a fresh instance of your class Quiz by calling bool correctAnswer = Quiz().getQuestionAnswer(); inside checkAnswer().
Try to store the Quiz instance ouside:
const myQuiz = Quiz();
void checkAnswer(bool userAnswer) {
bool correctAnswer = myQuiz.getQuestionAnswer();
setState(() {
if (userAnswer == correctAnswer) {
// right answer
} else {
// wrong pick
}
myQuiz.nextQuestion();
});
}

lodash mergeWith, skip with some key

function merger(objValue, srcValue, key, object, source, stack) {
switch (key) {
case 'keya':
case 'keyb':
case 'keyc':
return null
}
}
mergeWith({}, oldObj, newObj, merger)
I would like to skip merging when key is equal to some value. But the output from above code will have the output as {keya: null} when newObj has keya.
Can I skip the merge so that the key is not in the output?
Simple answer: It is not possible with _.mergeWith.
You can see here https://github.com/lodash/lodash/issues/2966. You have to delete the null valued properties again with another process. Like,
_.omitBy(mergedObj, _.isNull);
This can totally be done like this:
function customMerge(destination, source, skip) {
return _.mergeWith(
destination,
source,
(objValue, srcValue, key) => {
if (srcValue === skip) {
_.unset(destination, key);
}
}
);
}
Here's an implementation of omitDeep that will omit any key/value that passes the predicate anywhere in the object structure.
function omitDeep(value, predicate = (val) => !val) {
return _.cloneDeepWith(value, makeOmittingCloneDeepCustomizer(predicate))
}
function makeOmittingCloneDeepCustomizer(predicate) {
return function omittingCloneDeepCustomizer(value, key, object, stack) {
if (_.isObject(value)) {
if (_.isArray(value)) {
return _(value).reject(predicate).map(item => _.cloneDeepWith(item, omittingCloneDeepCustomizer))
}
const clone = {}
for (const subKey of Object.keys(value)) {
if (!predicate(value[subKey])) {
clone[subKey] = _.cloneDeepWith(value[subKey], omittingCloneDeepCustomizer)
}
}
return clone
}
return undefined
}
}

Collection find method doesn't work on Angular 2 recursive function

I'm developing Angular2 with Meteor.
When I make a little component with a recursive function, it has some weird error.
Here is my part of codes.
Not recursive - return a result
ngOnInit() {
//this.current_canvas return the right results
this.current_canvas = this.get_canvase(1);
}
get_canvase(which_canvas): Canvas[] {
if (!isNaN(which_canvas)) {
this.current_canvas_id = which_canvas;
return CanvasContents.find().map((messages: Canvas[]) => { return messages; })[0].content;
return '';
} else if(which_canvas == 'most-recent') {
this.get_canvase(1);
}
}
Recursive - Don't return a result
ngOnInit() {
//this.current_canvas Goes to NUll
this.current_canvas = this.get_canvase('most-recent');
}
get_canvase(which_canvas): Canvas[] {
if (!isNaN(which_canvas)) {
this.current_canvas_id = which_canvas;
console.log('this.current_canvas_id : ' + this.current_canvas_id);
return CanvasContents.find().map((messages: Canvas[]) => { return messages; })[0].content;
return '';
} else if(which_canvas == 'most-recent') {
this.get_canvase(1);
}
}
Have I used a wrong syntax? or is it on wrong Angular2 state to get right result?

How to pass a test if expect fails

I have this code
it('This should pass anyway', function (done) {
testObj.testIt(regStr);
});
testObj
this.testIt = function (regStr) {
selector.count().then(function (orgCount) {
for (var curr = 0; curr < count; curr++) {
checkField(curr, regStr);
}
});
};
function checkField(curr, regStr) {
selector.get(curr).all(by.tagName('li')).get(0).getInnerHtml().then(function (text) {
expect(text).to.match(regStr, curr + '#ERR');
});
}
If one of these expects get a failure, test fails. How can i handle this? I mean - can i somehow count passed and failed expect()ations and return it? or, at least, dont let test break on first error.
I've tried try-catch, but nothing good happened.
it('This should pass anyway', function (done) {
try {
testObj.testIt(regStr);
} catch (e) {
console.log('#err' + e);
}
});
And then i wanted to use done(), but havent found any examples to do the similar. Can u please help me?
Sry for my english
UPD
You can return either null or a string from checkField(), join them up, and expect the array to be empty:
this.testIt = function (regStr) {
selector.count().then(function (orgCount) {
var errors = [];
for (var curr = 0; curr < orgCount; curr++) {
var e = checkField(curr, regStr);
if (e) { errors.push(e); }
}
assert.equal(0, errors.length, errors);
});
};
A cleaner approach would be to use map() to collect the data into an array:
var data = selector.map(function (elm) {
return elm.element(by.tagName('li')).getText();
});
expect(data).toEqual(["test1", "test2", "test3"]);