I'm trying to get a copy of an object property then modify the copy but it turns out the source object was also modified. How can I prevent it?
void main() async{
var b = new B();
var l = await b.letters();
print(b._letters.toString());
l.removeWhere((l) => l == 'b');
print(l.toString());
print(b._letters.toString());
}
class B{
List<String> _letters = ['a','b','c'];
Future<List<String>> letters() async{
return _letters;
}
}
The above result is
[a, b, c]
[a, c]
[a, c]
But I want
[a, b, c]
[a, c]
[a, b, c]
You can create a copy with List.from:
class B {
List<String> _letters = ['a','b','c'];
Future<List<String>> letters() async {
// Copy the _letters list
return _letters.toList();
}
}
Related
I am ne to dart.
In python it was
[["A","B"],["C","D","E"],["F","G"]]
In dart It was Showing error Help me
If you are receiving the data, at runtime, in the mentioned form, you would not easily be able to use the spread operator, as the others have suggested.
Instead, you can use the expand function and create a new list based on this result like this:
void main() {
final list = [["A","B"],["C","D","E"],["F","G"]];
final list2 = [...list.expand((e) => e)];
print(list2); // [A, B, C, D, E, F, G]
}
void main() {
// example 1
print([...['A', 'B'], ...['C', 'D', 'E'], ...['F', 'G']]);
// output: [A, B, C, D, E, F, G]
// example 2
var characters1 = <String>['A', 'B'];
var characters2 = <String>['C', 'D', 'E'];
var characters3 = <String>['F', 'G'];
var allCharacters = [...characters1, ...characters2, ...characters3];
print(allCharacters);
// output: [A, B, C, D, E, F, G]
}
Read here for more about the spread operator ...
Just use spread operator '...'
[...["A","B"],...["C","D","E"],...["F","G"]]
Hope it helps
I'm working on some generic list utility functions and there seems to be an issue with the type inference for a generic function when the primary variables are lists. This is demonstrated with the following code:
List<T> combine<T>(List<T> a, List<T> b, T Function(T a, T b) combiner) {
final list = <T>[];
for (int i = 0; i < a.length && i < b.length; i++) {
list.add(combiner(a[i], b[i]));
}
return list;
}
void main() {
final a = [5, 8];
final b = [7, -3];
final c = combine(a, b, (a, b) => a + b); // Error
print(c);
// Expected: [12, 5]
}
When I use this code as-is, the type inference within the lambda sets a and b to be Object?, which results in the following error message:
The operator '+' can't be unconditionally invoked because the receiver can be 'null'.
Try adding a null check to the target ('!').
Doing what the error message says changes the message to the following:
The operator '+' isn't defined for the type 'Object'.
Try defining the operator '+'.
The issue obviously is that type inference is assigning the parameters to Object? instead of the expected int. This can be worked around by either typing the parameters or explicitly passing the generic type to the function:
final c = combine(a, b, (int a, int b) => a + b);
// OR
final c = combine<int>(a, b, (a, b) => a + b);
However, that's an added level of verbosity that I don't want to have to force the users of these utility functions to have to do (not to mention it will be a support issue when I have to explain to them to do this). Is there a way to change the function signature to make it so type inference works as expected?
This is basically Dart List.fold vs List.reduce type inference, but in your case you could sidestep the problem by making your function an extension method so that T is deduced from the receiver instead of from the arguments:
extension<T> on List<T> {
List<T> combineWith(List<T> b, T Function(T a, T b) combiner) {
final list = <T>[];
for (int i = 0; i < length && i < b.length; i++) {
list.add(combiner(this[i], b[i]));
}
return list;
}
}
void main() {
final a = [5, 8];
final b = [7, -3];
final c = a.combineWith(b, (a, b) => a + b); // Error
print(c);
// Expected: [12, 5]
}
I have some string conditions on my database, such as "==", "!=", ">", ">="... I want to use those conditions on my client side.
if (a myCondition b) print('ok')
How do I convert a string into an actual condition?
You will have to parse your string and perform the appropriate comparison manually. One way:
bool applyCondition(String comparison, dynamic a, dynamic b) {
switch (comparison) {
case '==':
return a == b;
case '!=':
return a != b;
case '>':
return a > b;
case '>=':
return a >= b;
// Other cases...
}
}
if (applyCondition(myCondition, a, b)) {
print('ok');
}
A slightly more compact (but likely less efficient) version with a Map instead of switch:
final comparatorTable = <String, bool Function(dynamic, dynamic)>{
'==': (a, b) => a == b,
'!=': (a, b) => a != b,
'>': (a, b) => a > b,
'>=': (a, b) => a >= b,
// Other cases...
};
if (comparatorTable[myCondition]!(a, b)) {
print('ok');
}
I've got more of my expression parser working (Dart PetitParser to get at AST datastructure created with ExpressionBuilder). It appears to be generating accurate ASTs for floats, parens, power, multiply, divide, add, subtract, unary negative in front of both numbers and expressions. (The nodes are either literal strings, or an object that has a precedence with a List payload that gets walked and concatenated.)
I'm stuck now on visiting the nodes. I have clean access to the top node (thanks to Lukas), but I'm stuck on deciding whether or not to add a paren. For example, in 20+30*40, we don't need parens around 30*40, and the parse tree correctly has the node for this closer to the root so I'll hit it first during traversal. However, I don't seem to have enough data when looking at the 30*40 node to determine if it needs parens before going on to the 20+.. A very similar case would be (20+30)*40, which gets parsed correctly with 20+30 closer to the root, so once again, when visiting the 20+30 node I need to add parens before going on to *40.
This has to be a solved problem, but I never went to compiler school, so I know just enough about ASTs to be dangerous. What "a ha" am I missing?
// rip-common.dart:
import 'package:petitparser/petitparser.dart';
// import 'package:petitparser/debug.dart';
class Node {
int precedence;
List<dynamic> args;
Node([this.precedence = 0, this.args = const []]) {
// nodeList.add(this);
}
#override
String toString() => 'Node($precedence $args)';
String visit([int fromPrecedence = -1]) {
print('=== visiting $this ===');
var buf = StringBuffer();
var parens = (precedence > 0) &&
(fromPrecedence > 0) &&
(precedence < fromPrecedence);
print('<$fromPrecedence $precedence $parens>');
// for debugging:
var curlyOpen = '';
var curlyClose = '';
buf.write(parens ? '(' : curlyOpen);
for (var arg in args) {
if (arg is Node) {
buf.write(arg.visit(precedence));
} else if (arg is String) {
buf.write(arg);
} else {
print('not Node or String: $arg');
buf.write('$arg');
}
}
buf.write(parens ? ')' : curlyClose);
print('$buf for buf');
return '$buf';
}
}
class RIPParser {
Parser _make_parser() {
final builder = ExpressionBuilder();
var number = char('-').optional() &
digit().plus() &
(char('.') & digit().plus()).optional();
// precedence 5
builder.group()
..primitive(number.flatten().map((a) => Node(0, [a])))
..wrapper(char('('), char(')'), (l, a, r) => Node(0, [a]));
// negation is a prefix operator
// precedence 4
builder.group()..prefix(char('-').trim(), (op, a) => Node(4, [op, a]));
// power is right-associative
// precedence 3
builder.group()..right(char('^').trim(), (a, op, b) => Node(3, [a, op, b]));
// multiplication and addition are left-associative
// precedence 2
builder.group()
..left(char('*').trim(), (a, op, b) => Node(2, [a, op, b]))
..left(char('/').trim(), (a, op, b) => Node(2, [a, op, b]));
// precedence 1
builder.group()
..left(char('+').trim(), (a, op, b) => Node(1, [a, op, b]))
..left(char('-').trim(), (a, op, b) => Node(1, [a, op, b]));
final parser = builder.build().end();
return parser;
}
Result _result(String input) {
var parser = _make_parser(); // eventually cache
var result = parser.parse(input);
return result;
}
String parse(String input) {
var result = _result(input);
if (result.isFailure) {
return result.message;
} else {
print('result.value = ${result.value}');
return '$result';
}
}
String visit(String input) {
var result = _result(input);
var top_node = result.value; // result.isFailure ...
return top_node.visit();
}
}
// rip_cmd_example.dart
import 'dart:io';
import 'package:rip_common/rip_common.dart';
void main() {
print('start');
String input;
while (true) {
input = stdin.readLineSync();
if (input.isEmpty) {
break;
}
print(RIPParser().parse(input));
print(RIPParser().visit(input));
}
;
print('done');
}
As you've observed, the ExpressionBuilder already assembles the tree in the right precedence order based on the operator groups you've specified.
This also happens for the wrapping parens node created here: ..wrapper(char('('), char(')'), (l, a, r) => Node(0, [a])). If I test for this node, I get back the input string for your example expressions: var parens = precedence == 0 && args.length == 1 && args[0] is Node;.
Unless I am missing something, there should be no reason for you to track the precedence manually. I would also recommend that you create different node classes for the different operators: ValueNode, ParensNode, NegNode, PowNode, MulNode, ... A bit verbose, but much easier to understand what is going on, if each of them can just visit (print, evaluate, optimize, ...) itself.
I have a file like:
A
B
C
D
Both readAsLines() and readAsString() + string.split('\n') give me:
[A, B, , , C, D]
What is the smartest way to get?
[A,B,C,D]
One possibility would be:
import 'dart:io';
main() {
File f = new File('test.txt');
f.readAsLines().then((List<String> lines) {
print(lines.where((String s) => s.isNotEmpty));
});
}