Break on ForEach() dart - flutter

I'm writing a function where I iterate thru a map and look test for valid values on an function. My question is there is a better way to correctly break from a foreach loop when an error is found?
('break' does not work on foreach())
Since I am not able to use the break function here so i had to place a bool marker :/
Any help in making this code nice looking would be appreciated :)
Future<bool> saveToKeychainFunc(Map data) {
bool saved = false;
bool error = false;
data?.keys?.forEach((item) async {
if (data[item] != null) {
await _storage.write(key: item.toString(), value: data[item].toString());
} else {
//TODO
// data error, we got null for a value!
error = true;
}
saved = true;
});
return (error == true) ? false : saved;
}

I've experienced this. My work around is using for loop instead.
ex:
for (int i = 0; i < jsonTransactions.length; i++) {
Transaction transaction = Transaction.fromJson(jsonTransactions[i]);
transactions.add(transaction);
}
You can just add conditions, and add your break inside the loop if conditions are met. Since you're using a map, my code should not be very different since Map also has .length

Related

"map.getOrDefault" equivalent in Dart

I'm working on a friend suggestion algorithm for a flutter social media application. I'm still an amateur when it comes to Dart so I'm stuck on the following line of code:
class FriendSuggestionAlgorithm {
User friendSuggestion(User user) {
int max = -1;
User suggestion;
Map<User, int> map = new HashMap();
for (User friend in user.friends) {
for (User mutualFriend in friend.friends) {
if (mutualFriend.id != user.id && !user.friends.contains(mutualFriend)) {
map.putIfAbsent(mutualFriend, map.getOrDefault(mutual, 0) + 1);
}
}
}
for (MapEntry<User, int> mutualFriend in map.entries) {
if (mutualFriend.value > max) {
max = mutualFriend.value;
suggestion = mutualFriend.key;
}
}
return suggestion;
}
}
map.getOrDefault is underlined (I know the method doesn't exist in Dart). Do you know what the equivalent is in Dart? (PS, I'm just translating Java code into Dart.
Any help is appreciated!
Your code doesn't make sense. map.putIfAbsent will do work only if the key doesn't exist, so the hypothetical map.getOrDefault call with the same key would always return the default value anyway. That is, your logic would be the equivalent of map.putIfAbsent(mutual, () => 1), where nothing happens if the key already exists.
Map.putifAbsent takes a callback as its argument to avoid evaluating it unless it's actually necessary. I personally prefer using ??= when the Map values are non-nullable.
I presume that you actually want to increment the existing value, if one exists. If so, I'd replace the map.putIfAbsent(...) call with:
map[mutual] = (map[mutual] ?? 0) + 1;
Also see: Does Dart have something like defaultdict in Python?
You could do it like this:
map.putIfAbsent(mutual, (map.containsKey(mutual) ? map[mutual] : 0) + 1)
Maybe take a look at this for more info: https://dart.dev/guides/language/language-tour#conditional-expressions
Edit:
This code should work
class FriendSuggestionAlgorithm {
User? friendSuggestion(User user) {
int max = -1;
User? suggestion;
Map<User, int> map = {};
for (User friend in user.friends) {
for (User mutualFriend in friend.friends) {
if (mutualFriend.id != user.id && !user.friends.contains(mutualFriend)) {
map.putIfAbsent(mutualFriend, () => (map[mutualFriend] ?? 0) + 1);
}
}
}
for (MapEntry<User, int> mutualFriend in map.entries) {
if (mutualFriend.value > max) {
max = mutualFriend.value;
suggestion = mutualFriend.key;
}
}
return suggestion;
}
}
Note that suggestion nullable because it could happen that suggestion is never assigned. And therefore friendSuggestion(user) can return null;
To come back to your question
the correct code is
map.putIfAbsent(mutualFriend, () => (map[mutualFriend] ?? 0) + 1);
My mistake on my original answer, the ifAbsent part of this is a function. In the function the value of mutualFriend is retrieved. If that is null use 0.

Backtracking results in same repeating course

I am trying to solve a puzzle, and it has been suggested that I use backtracking - I did not know the term so did some investigation, and found the following in Wikipedia:
In order to apply backtracking to a specific class of problems, one must provide the data P for the particular instance of the problem that is to be solved, and six procedural parameters, root, reject, accept, first, next, and output. These procedures should take the instance data P as a parameter and should do the following:
root(P): return the partial candidate at the root of the search tree.
reject(P,c): return true only if the partial candidate c is not worth completing.
accept(P,c): return true if c is a solution of P, and false otherwise.
first(P,c): generate the first extension of candidate c.
next(P,s): generate the next alternative extension of a candidate, after the extension s.
output(P,c): use the solution c of P, as appropriate to the application.
The backtracking algorithm reduces the problem to the call backtrack(root(P)), where backtrack is the following recursive procedure:
procedure backtrack(c) is
if reject(P, c) then return
if accept(P, c) then output(P, c)
s ← first(P, c)
while s ≠ NULL do
backtrack(s)
s ← next(P, s)
I have attempted to use this method for my solution, but after the method finds a rejected candidate it just starts again and finds the same route, rather than the next possible one.
I now don't think I have used the next(P,s) correctly, because I don't really understand the wording 'after the extension s'.
I've tried 2 methods:
(a) in the first() function, generating all possible extensions, storing them in a list, then using the first. The next() function then uses the other extensions from the list in turn. But this maybe can't work because of the calls to backtrack() in between the calls to next().
(b) adding a counter to the data (i.e. the class that includes all the grid info) and incrementing this for each call of next(). But can't work out where to reset this counter to zero.
Here's the relevant bit of code for method (a):
private PotentialSolution tryFirstTrack(PotentialSolution ps)
{
possibleTracks = new List<PotentialSolution>();
for (Track trytrack = Track.Empty + 1; trytrack < Track.MaxVal; trytrack++)
{
if (validMove(ps.nextSide, trytrack))
{
ps.SetCell(trytrack);
possibleTracks.Add(ps);
}
}
return tryNextTrack(ps);
}
private PotentialSolution tryNextTrack(PotentialSolution ps)
{
if (possibleTracks.Count == 0)
{
ps.SetCell(Track.Empty);
return null;
}
ps = possibleTracks.First();
// don't use same one again
possibleTracks.Remove(ps);
return ps;
}
private bool backtrackTracks(PotentialSolution ps)
{
if (canExit)
{
return true;
}
if (checkOccupiedCells(ps))
{
ps = tryFirstTrack(ps);
while (ps != null)
{
// 'testCells' is a copy of the grid for use with graphics - no need to include graphics in the backtrack stack
testCells[ps.h, ps.w].DrawTrack(g, ps.GetCell());
if (ps.TestForExit(endColumn, ref canExit) != Track.MaxVal)
{
drawRowColTotals(ps);
return true;
}
ps.nextSide = findNextSide(ps.nextSide, ps.GetCell(), ref ps.h, ref ps.w);
if (ps.h >= 0 && ps.h < cellsPerSide && ps.w >= 0 && ps.w < cellsPerSide)
{
backtrackTracks(ps);
ps = tryNextTrack(ps);
}
else
return false;
}
return false;
}
return false;
}
and here's some code using random choices. This works fine, so I conclude that the methods checkOccupiedCells() and findNextSide() are working correctly.
private bool backtrackTracks(PotentialSolution ps)
{
if (canExit)
{
return true;
}
if (checkOccupiedCells(ps))
{
Track track = createRandomTrack(ps);
if (canExit)
return true;
if (track == Track.MaxVal)
return false;
ps.SetCell(track);
ps.nextSide = findNextSide(ps.nextSide, track, ref ps.h, ref ps.w);
if (ps.h >= 0 && ps.h < cellsPerSide && ps.w >= 0 && ps.w < cellsPerSide)
backtrackTracks(ps);
else
return false;
}
}
If it helps, there's more background info in the puzzle itself here

Dart / Flutter : Waiting for a loop to be completed before continuing... (Async Await?)

I have a function which creates a sublist from a large(very large list). After creating this list, the function goes on treating it (deleting duplicates, sorting...).
As long as the list was not too big, it worked fine. But now, I get "The Getter length was called on null". I suppose, it's because the second part of the function (after the loop) starts before the sublist is completed... so it doesn't work...
How can we force the function to wait for the loop to be over to continue the rest of the treatment ?
Is it with Async /Await ? Or can we do something like "While... something is not over...", or "As soon as something is done... do that" ? (My suggestions might be naive, but I am a beginner...)
Here is the code :
List themeBankFr() {
List<Map> themeBankFr = [];
for (Word word in wordBank) {
for (Thematique wordTheme in word.theme) {
themeBankFr.add({
'themeFr': wordTheme.themeFr,
'image': wordTheme.image,
});
}
}
// convert each item to a string by using JSON encoding
final jsonList = themeBankFr.map((item) => jsonEncode(item)).toList();
// using toSet - toList strategy
final uniqueJsonList = jsonList.toSet().toList();
// convert each item back to the original form using JSON decoding
final result = uniqueJsonList.map((item) => jsonDecode(item)).toList();
// sort the list of map in alphabetical order
result.sort((m1, m2) {
var r = m1['themeFr'].compareTo(m2['themeFr']);
if (r != 0) return r;
return m1['image'].compareTo(m2['image']);
});
return result;
}
i think i have a good answer that may helps you and it will as following
first create another function to do the work of for loops and this function returns a future of list that you need like below
Future<List<Map>> futureList(List wordBank){
List<Map> themeBankFr = [];
for (Word word in wordBank) {
for (Thematique wordTheme in word.theme) {
themeBankFr.add({
'themeFr': wordTheme.themeFr,
'image': wordTheme.image,
});
}
}
return Future.value(themeBankFr);
}
after that you can use this function inside your code and use it as async await and now you will never run the below lines before you return this array like below
List themeBankFr() async {
List<Map> themeBankFr = await futureList(wordBank);
// convert each item to a string by using JSON encoding
final jsonList = themeBankFr.map((item) => jsonEncode(item)).toList();
// using toSet - toList strategy
final uniqueJsonList = jsonList.toSet().toList();
// convert each item back to the original form using JSON decoding
final result = uniqueJsonList.map((item) => jsonDecode(item)).toList();
// sort the list of map in alphabetical order
result.sort((m1, m2) {
var r = m1['themeFr'].compareTo(m2['themeFr']);
if (r != 0) return r;
return m1['image'].compareTo(m2['image']);
});
return result;
}
i think this will solve your problem and i hope this useful for you

What is the most efficient way to call another function in parent function to execute Palindrome function?

In programming, there are multiple ways of doing the same problem. The following problem is in regards to palindrome. Though I feel that I am on the right track, I am not able to completely solve the problem to get to requested solution.
What is a palindrome? A word written forward or backward is the same and returns true. Example, "racecar". Hence, I designed the following code in Javascript...
function palindrome(string) {
string = string.toLowerCase();
lowString = string.toLowerCase().split("").reverse().join("");
for (var i=0; i<string.length; i++) {
if (string[i] !== lowString[i]) {
return false;
}
}
}
return true;
}
The above code returns true if Palindrome exists and returns false if not.
Then, the problem says - Given various palindrome in a string or array, please return the longest palindrome. So, I wrote the following:
function longestPalindrome(newstring) {
splitString = newString.split(" ");
for (var i=0; i < splitString; i++) {
if (splitString[i] == palindrome(splitString[i]) {
console.log(splitString[i]);
}
}
}
longestPalindrome("This is a racecar ada");'
But in the above code, I am not able to get the required outcome because I believe I am not calling the function correctly.
I would appreciate clear directions or even a solution built off of my track as well as the track you deem fittest.

How can I get an alert if a specific url substring is present and nothing if null

function getCode() {
if (window.location.href.indexOf("?discount=")) {
var url = (document.URL);
var id = url.substring(url.lastIndexOf('=') + 1);
window.alert(id);
return true;
} else {
return false;
}
}
Purpose: When people go to our "Service Request" page using a QR code that has a substring of ?discount=1234. I have been testing by creating an alert box with the discount code showing. Eventually I want to be able to populate that "1234" automatically into a "Discount Code:" text field on page load.
The above is a mixture of a few suggestions when I researched it.
Result: Going to example.com/serviceRequest.html?discount=1234 gives me the appropriate alert "1234", as I want... Going to example.com/serviceRequest.html gives me the alert http://example.com/serviceRequest.html, but I don't want anything to happen if "?discount=" is null.
Any suggestions?
indexOf returns -1 if the search pattern doesn't exist. In JavaScript, anything not a 0 or false or undefined is considered true.
So your line of:
if(window.location.href.indexOf("?discount=")) {
Would better search as:
if(window.location.href.indexOf("?discount=") > -1) {
Try changing your if-statement to:
if(window.location.href.indexOf("?discount=") != -1)
Look up the documentation for ".indexOf". It returns -1 for not found and >= 0 if it is found.
...indexOf("?discount=") >= 0
substring and indexOf return -1 if the text is not found, so you can test for this. E.g.
function getCode() {
if(window.location.href.indexOf("?discount=") != -1) {
var url = (document.URL);
var id = url.substring(url.lastIndexOf('=') + 1);
window.alert(id);
return true;
}
else {
return false;
}
}
You just need to test the indexOf value:
function getCode() {
if (window.location.href.indexOf("?discount=") !== -1) {
var url = (document.URL);
var id = url.substring(url.lastIndexOf('=') + 1);
window.alert(id);
return true;
}
else {
return false;
}
}
So the quick and dirty answer would be
var discount = window.location.search.split("?discount=")[1];
alert(discount);
But this doesn't take into account the occurence of other query string parameters.
You'll really want to parse all the query parameters into a hash map.
This article does a good job of showing you a native and jQuery version.
http://jquery-howto.blogspot.com/2009/09/get-url-parameters-values-with-jquery.html