Searching for a solution for more memory friendly way while adding elements to a list of class in flutter/dart - flutter

I'm trying to produce a runtime table. Below class and codes are simplified version of my final purpose.
class AppModel {
int appID;
String appName;
AppModel({this.appID, this.appName});
}
I'm calculating, fetching some another data and trying to fill the following object like this:
// _newApps value is between 1-30 mostly but not limited
List<AppModel> theList = [];
for (int i = 0; i < _newApps; i++) {
AppModel _newRecord = AppModel();
_newRecord.appID = _getNewAppID();
_newRecord.appName = _getNewAppName();
theList.add(_newRecord);
}
So the question is the code creates a new AppModel instance for only adding the element to the list for every iteration inside the for loop. According to my program logic, this event can be repeated 100-150 times sometimes.
Is it normal or is there any more memory efficient way to do so?
Thank you in advance.

I would like to point out (a better approach) that instead of for Loop you could have used the map method on the Apps List you have. And instead of creating a object every time in the Loop create a constructor for returning the object instance using the required details.
Hope you find it useful.

Related

Added row moves to last position once filter is removed

In NatTable I am adding a row in filtered table. After removing the filter, the newly added row moves to last position in the table.
But I want to it to stay in the same position, that is next to the row which I added when the table is filtered.
I am currently using the RowInsertCommand. I don't want to add row via model or list which used to populated the table. I want to achieve only via NatTable commands. Is it possible?
It is always hard to follow the explanations and the issue without example code. But I assume you simply copied code from the NatTable examples, so I will explain your issue based on that.
First, the RowInsertCommand has several constructors. If you are using a constructor without a rowIndex or rowPositionparameter, the new object will ALWAYS be added at the end of the list.
When using the filter functionality in NatTable with GlazedLists, the list that is wrapped in the body DataLayer is the FilterList. If you are operating on the FilterList for calculating the rowIndex where the new object should be added and have the FilterList as base list in the RowInsertCommandHandler, the place where the new object is added is transformed between the FilterList and the base EventList, which might not be the desired result.
To solve this you need to create the RowInsertCommandHandler by using the base EventList.
EventList<T> eventList = GlazedLists.eventList(values);
TransformedList<T, T> rowObjectsGlazedList = GlazedLists.threadSafeList(eventList);
SortedList<T> sortedList = new SortedList<>(rowObjectsGlazedList, null);
this.filterList = new FilterList<>(sortedList);
this.baseList = eventList;
bodyDataLayer.registerCommandHandler(new RowInsertCommandHandler<>(this.baseList));
The action that performs the add operation then of course needs to calculate the index based on the base EventList. The following code is part of the SelectionAdapter of an IMenuItemProvider:
int rowPosition = MenuItemProviders.getNatEventData(event).getRowPosition();
int rowIndex = natTable.getRowIndexByPosition(rowPosition);
Object relative = bodyLayerStack.filterList.get(rowIndex);
int baseIndex = bodyLayerStack.baseList.indexOf(relative);
Object newObject = new ...;
natTable.doCommand(new RowInsertCommand<>(baseIndex + 1, newObject));

How to perform deep copy for a list to another list without affecting the original one in Flutter

I have two lists of Type object, _types and _filteredTypes:
List<Type> _types = []; // Original list
List<Type> _filteredTypes = []; // Where i bind filter the contents
a Type object is:
class Type extends Equatable {
final int id;
final String title;
List<SubType>? subTypes;
Type({
required this.id,
required this.title,
this.subTypes,
});
}
a SubType object is:
class SubType extends Equatable {
final int id;
final String title;
Type({
required this.id,
required this.title,
});
}
I need to filter the list based on search text, so whenever user types a letter the _filteredTypes being updated.
I do the filter on _onSearchChangedEvent() within setState() like this:
_filteredTypes = List.from(_types); // To get the original list without filter
for(var i = 0; i < _filteredTypes.length; i++) {
// This is where i filter the search result when a subType.title matches the search query:
_filteredTypes[i].subTypes = List.from(_types[i].subTypes!.where((element) => element.title.toLowerCase().contains(query!.toLowerCase())).toList());
}
// This is where i filter the search result and remove any type doesn't match any subType.title:
_filteredTypes.removeWhere((element) => element.subTypes!.length == 0);
bindTypes(); // To refresh the list widget
The problem is when i need get the original list i get the main type but type.subTypes is still filtered based on the previous search not the original one! even it is copied without reference _filteredTypes = List.from(_types);
It seems like a bug in Flutter, any idea guys?
List.from does not provide you with a deep copy of _types- it gives you a shallow copy. Meaning both _filteredTypes and _types share the same subTypes. It's similar in that behavior to this example
var sharedList = [1];
final listOne = [1, sharedList];
final listTwo = [1, sharedList];
sharedList[0] = 2;
Changing sharedList will change the value in both listOne and listTwo. If shared list was just an integer, changing that integer would not produce the same effect. Like in this example:
var sharedInteger = 1;
final listOne = [1, sharedInteger];
final listTwo = [1, sharedInteger];
sharedInteger = 2;
When you create an instance of a class may it be built in like List or your own custom class, what you get returned is a reference or a pointer to that instance/object. The object itself is allocated on the heap memory area rather than on the stack which means that this object can be referenced outside of functions. As in its life (object life) is not bound by the scope of the function so when you reach the end } of the function the object still exists, and its memory is freed by a special program called the garbage collector.
In dart as in many modern programming languages garbage collectors are used and objects are automatically allocated on the heap. In languages such as C++ for example you can allocate objects on the stack, and you have to be explicit about heap allocation, and deallocate any objects on the heap when you are done with them.
All of the above you can look up the gist of it is since subtypes is a list, it's a reference type so both _filteredTypes and _types have that reference. If you want a deep copy you can do that as well, and I'll leave it for you to look that up.
This is how to perform a deep copy for a list has sub-list, thanks moneer alhashim, your answer guided me.
I'm posting it as an answer to help someone else find the solution easy.
So, the key here is to map the original list types.map(...) and fill it manually instead of using List.from(), and that will create a new instance for deep objects.
First, i declared one function for each list:
//For the parent list:
List<Types> getNewTypesInstance {
// This function allows to perform a deep copy for the list.
return types.map((e) =>
Type(id: e.id, title: e.title, subTypes: e.subTypes))
.toList();
}
// For the child list:
List<SubType> getNewSubTypesInstance(List<SubType> lst) {
// This function allows to perform a deep copy for the list:
return lst.map((e) =>
SubType(id: e.id, title: e.title))
.toList();
}
And if you have more deep list(s), you will need third function to obtain it as new instance and so on.
Finally, the way how to call them is to write this code within setState():
_filteredTypes = getNewTypesInstance
for(var i = 0; i < _filteredTypes.length; i++) {
// This is where i filter the search result when a subType.title matches the search query:
_filteredTypes[i].subTypes = List.from(getNewSubTypesInstance(_types[i].subTypes!.where((element) => element.title.toLowerCase().contains(query!.toLowerCase())).toList()));
}
// This is where i filter the search result and remove any type doesn't match any subType.title:
_filteredTypes.removeWhere((element) => element.subTypes!.length == 0);
bindTypes(); // To refresh the list widget

Is there no simple way to make a deep of lists in flutter?

I tried List.from and [...orginalObject], but neither does a deep copy. In both cases it's clearly just copying the references. Which means if I change any data in the list in which I copied the data, the original data gets changed too.
It seems to me that the only way to do a for loop and define each of the entries the copied list with a new operator and the data from each of corresponding entries from the original list. Something as shown in the following image.
Seems like quite a tedious approach. Is there any simpler approach?
Thanks.
In vanilla Dart, not really, since this would require the ability to copy the leaf objects, and there is no way for the language to know how to do that for arbitrary objects.
However, the built_value and built_collection packages may solve your issue. One of their main features is deep immutability. First, you write your classes like this:
class Item {
final String foo;
final int bar;
Item(this.foo, this.bar);
}
// becomes
part 'item.g.dart';
abstract class Item extends Built<Item, ItemBuilder> {
Item._();
factory Item([void Function(ItemBuilder) updates]) = _$Item;
// boilerplate, can use tooling to auto-generate
String get foo;
int get bar;
}
This lets you create an immutable object using a mutable Builder and then finalizing it, e.g.:
final item1 = Item((b) {
// here b is an ItemBuilder, the mutable version of Item
b.foo = 'Hello';
b.bar = 123;
});
final item2 = item1.rebuild((b) => b.foo = 'New Value'); // Item(foo: 'New Value', bar: 123)
You can then use built_collection to work with deeply immuatble collections of built values, e.g.:
final list = BuiltList<Item>([item1, item2, item3]);
final deepCopy = list.rebuild((b) {}); // rebuild with no changes
final withNewElement = list.rebuild((b) => b.add(item4));
The important thing with all of these is that they are all immutable, and are "value objects", meaning (among other things) that they are considered equal if all their corresponding values are equal. You can consider each rebuild call to be returning you a brand new list with all the values copied over.
In fact, the library is smart enough to only create new objects for values that have actually changed, but because it is immutable, it acts like a deep copy, without the potential performance costs.
The main downside with these libraries is that they rely on code generation, so it requires a bit more setup than just putting it in your dependencies. In return, you get a lot of useful features in addition to having deeply immutable objects (like json serialization, null checking in pre-null-safety code, #memoized to cache results of expensive computations`, etc)
Dart does not have copy constructors nor have required clone() methods on objects, so there is no way to copy an arbitrary object, and therefore there is no way to make a deep copy of a collection of arbitrary objects.
cameron1024's answer suggesting the use of package:built_value and package:built_collection is good. If they're not suitable for you, however, you could make a function that copies elements via a callback:
List<T> copyList<T>(Iterable<T> items, T Function(T element) copier) {
return [
for (var item in items) copier(item),
];
}
class Foo {
int i;
String s;
Foo(this.i, this.s);
#override
String toString() => 'Foo($i, "$s")';
}
void main() {
var list = [Foo(1, 'one'), Foo(2, 'two'), Foo(3, 'three')];
print('Original: $list');
var copy = copyList<Foo>(list, (foo) => Foo(foo.i, foo.s));
list[0].i = 100;
print('Mutated: $list');
print('Copy: $copy');
}

Can an object be assigned to a list without instancing that object?

This is an optimisation question.
I have a class with ~500 named constructors that i need to access through a list - the different constructors have to be picked at random based on specific criteria at runtime.
The constructors have the form:
stuff.s0 (){
<data>
<generating code>
}
The list is initialised with:
var stuffList = [stuff.s0(), stuff.s1(), ...., stuff.s500()];*
Is this creating 500 instances of 'stuff', or is an instance of 'stuff' only created when I use currentStuff = stuffList[42]? If it's the former, is there a better way to do this since only a small fraction of the 500 will be used during any one use of the application?
The data elements are declared as static const so they can be accessed without creating an instance, something similar would be good.
Also, is Dart good at garbage collection? So currentStuff = stuffList[14] would 'replace' stuff.s42 with stuff.s14 in memory, or does that instance of stuff.s42 need flagging as finished with somehow?
Thanks
The objects are created immediately.
All Dart objects are reference values, so assigning currentValue = something; will only change the variable to reference a different object.
What I would do is to have a list of constructor invocations:
var stuffs = [
() => stuff.s0(),
() => stuff.s1(),
// ...
() => stuff.s500(),
];
and then call the function when I access the list:
var currentValue = stuffs[5]();
This would not create the objects until you need them, and it would not keep them alive after you stop referencing them. On the other hand, if you need stuffs[5]() twice, it will build a new object each time.

List/Object searching in CoffeeScript

I'm trying to get my head around using CoffeeScript comprehensions as efficiently as possible. I think I have basic mapping down -- turning one list into another -- but searching still seems verbose to me.
Say I have a map of items to shops:
shopMap:
toyStore: ["games", "puzzles"]
bookStore: ["novels", "picture books"]
and, given an item, I want to find out which shop it's in. What's the best way of doing that in CoffeeScript?
Here's how I could do in in JavaScript:
var shop = findShop(item);
function findShop(item) {
for (shop in shopMap)
itemList = shopMap[shop]
for (i = 0, ii = itemList.length; i<ii; i++) {
if (itemList[i] === item) {
return shop;
}
}
}
}
I used a function to allow it to quickly break out of the loops with the return statement, instead of using breaks, but the function is kind of fugly as this is only being used once.
So is there a shorter CS equivalent preferably one that doesn't require creating a new function?
You can try this:
findShop = (item) ->
for shop, items of shopMap
return shop if item in items
If you really want to try with a list comprehension, this is equivalent:
findShop = (item) ->
(shop for shop, items of shopMap when item in items)[0]
But i think the first one reads better (and also doesn't need to generate an intermediate array for the results). This would be a better approach IMO if you wanted to find all shops for a given item:
findShops = (item) ->
shop for shop, items of shopMap when item in items
If this is a common operation, you might be better off creating an intermediate data structure up front and doing the lookup directly.
shopMap =
toyStore: ["games", "puzzles"]
bookStore: ["novels", "picture books"]
categoryMap = {}
for k, v of shopMap
for category in v
categoryMap[category] = k
alert(categoryMap['puzzles'])
Demo
With this implementation you need to loop through the structure only once up front (plus possibly update it if shopMap changes). With yours and epidemian's answer, you have to loop every time you need to do this particular type of lookup. If you do this operation a lot, it could make a difference. On the other hand, if your shopMap is really large (like thousands of entries), then my implementation will take up more memory.
Depending upon how robust you want to make this, you might want to turn it into a Class and have any operations on it occur through the Class' interface. You'd need addCategory and deleteCategory methods as well as a getStoreFromCategory method, which is essentially what we are implementing above. This object-oriented approach would hide the internal data-structure/implementation so you could later alter the implementation to optimize for memory or speed.