The Flutter Hashmap<String, List<CustomObject>> is overwriting the List type in the Hashmap on every add - flutter

The Flutter Hashmap<String, List > is overwritting the List type in the Hashmap on every single unique Key. So basically the code looks like:
HashMap<String, List<Jobs> > ElementJobMap = new HashMap<String, List<Jobs> >();
for (int i = 0; i < _JobsList.length; i++) {
String Key = _JobsList[i].elementID.toString();
if (ElementJobMap.containsKey(Key)) {
if (Key == _JobsList[i].elementID.toString()) {
ElementJobMap.update(Key, (value) {
value.add(_JobsList[i]);
return value;
});
}
} else {
ElementJobMap[Key] = tmpList;
}
}
So if there are two different String keys and each key has a unique list filled with several values in each. If I write to the List every instance is updated and so it is all the same data. Should be noted this code might have pointless stuff in it, but I've just been spitballing for awhile now.

ElementJobMap[Key] = tmpList;
You seem to be adding the exact same list instance as a base of every entry. Then you add to this single instance. If you want your hashmap to hold a different list instance for every key, you need to actually create one.
That said, you should probably look into grouping methods provided through packages, there is no point in trying to do it manually.

Related

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

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

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.

How can I create Hierarchical Container in Vaadin when I am having the duplicate ItemIds? If No, What is the alternate?

I want to create a tree of user with n level Hierarchy. I have a POJO object and within that I have id,parent_id.
The problem is user can belong in more than 1 group. So, when I am trying to do,
while (iterator.hasNext()) {
val user_pojo_obj = iterator.next()
val key = user_pojo_obj.id
val parent_key = user_pojo_obj.family_id
var child: Item = container.addItem(key)
child.getItemProperty("caption").asInstanceOf[Property[Any]].setValue(user_pojo_obj.name)
child.getItemProperty("POJOobj").asInstanceOf[Property[Any]].setValue(user_pojo_obj)
container.setParent(key, parent_key)
}
I got NullPointerException at the 2nd line, As per my knowledge it because of the addItem() duplication in container, which returns null.
Please suggest me the alternate if this can not be improve. (Using Scala)
Thanxx..
As far as I know, you can not have multiple parents or duplicate itemIds. The following pseudo-code is an alternate solution which builds the tree-like structure (node is your POJO):
counter = 0;
function process(nodes, parent) {
foreach (node in nodes) {
newId = counter++;
item = container.addItem(newId);
// set item caption etc.
if (parent not null)
container.setParent(newId, parent)
process(getNodesWithParent(node), newId);
}
}
process(getNodesWithParent(null), null);
The method getNodesWithParent needs to be defined by you. I guess you will take the iterator, iterate through your POJOs and return those with family_id equals the parameter's id. The overall performance depends on your implementation of getNodesWithParent, so if you have a large data set you should care to be efficient.

Spring Batch - Invoke read() method in Reader multiple times

I am trying to implement calling read() method in the itemReader multiple times.
For Eg:
I have a list of POJO in which I will have one string variable with values either A or B or C.
I have to sort this list based on alphabetical order and segment it into three list for each value. i.e., list for value A and list for value B
and list for value C.
I need to send each list to the read() method in the itemReader one by one.
Once List for A is processed and write, then I need to send List for B and so on..
Is this doable? Any help is appreciated.
Although I am not very clear on what you are trying to achieve, I don't see any reason it cannot be done.
I assume you mean either of this:
1. You want the "item" to be process to be a whole list of POJO with same ABC Type, or
2. You want the item to be the POJO itself, and you want them to be processed in order of ABC Type
2 is straight-forward. At the first read, prepare all the POJOs, sort it. I assume they are in some kind of
In psuedo code, it looks like this
class MyReader implements ItemReader<MyPojo> {
private List<MyPojo> values;
MyPojo read() {
if (values == null) {
values = getPojos();
sort values;
}
if (values.isEmpty()){
return null;
} else {
return values.popFront();
}
}
}
1 is nothing more complicated. You will need to group POJOs with same ABC type in same list, and return the lists one by one. It can be easily done by using a TreeMap<String, List<MyPojo>>
In psuedo code, it looks like this
class MyReader implements ItemReader<List<MyPojo>> { // note the item is List<MyPojo>
private NavigableMap<String, List<MyPojo>> values;
List<MyPojo> read() {
if (values == null) {
values = new TreeMap<>();
pojos = getPojos();
for (pojo : pojos) {
if (values do not contain pojo.abcType() ) {
values.put(pojo.abcType(), new ArrayList(pojo));
} else {
values.get(pojo.abcType()).add(pojo);
}
}
}
if (values.isEmpty()){
return null;
} else {
return values.popFirstEntry().value();
}
}
}
If your list of items is fully available (you have a List<Pojo> loaded with all items) you can:
use a ListItemReader and inject into the ordered list
use a custom ItemReader and sort items after first ItemReader.read()
About break the best way is to use a custom CompletionPolicy based on pojo 'string variable'; in this manner your writer will receive a list where POJO's 'string variable' has the same values for all list items (check How to read csv lines chunked by id-column with Spring-Batch? for sample code).

DataReader with duplicate column names

What is the best way of handling trying to get data from a DataReader that has more than one column with the same name?
Because of the amount of work involved and because we don't want to lose support from a vendor by changing the stored procedures we are using to retrieve the data, I am trying to find another way to get access to a column that shows up more than once in a datareader without having to rewrite the stored procedures.
Any Ideas?
EDIT:
Ok, the function that actually populates from a datareader is used in multiple places so there is a possibility that the function can be called by different stored procedures. What I did was to do a GetName using the index to check if it is the correct column, and if it is, then pull its value.
If you know the index of the column, then access it by the index.
Can't you use column ordinals? 0 for the 1st, 1 for the 2nd, and so on?
You will have to reference the column by index no; i.e. reader[5].ToString(); to read the data in column 5.
Based on original poster's approach described in the "Edit" paragraph, here's an extension method that will give the value based on the column name and the index of that name, e.g., 0 for the first instance of name, 1 for the second, etc:
using System;
namespace WhateverProject {
internal static class Extentions {
// If a query returns MULTIPLE columns with the SAME name, this allows us to get the Nth value of a given name.
public static object NamedValue(this System.Data.IDataRecord reader, string name, int index) {
if (string.IsNullOrWhiteSpace(name)) return null;
if (reader == null) return null;
var foundIndex = 0;
for (var i = 0; i < reader.FieldCount; i++) {
if (!reader.GetName(i).Equals(name, StringComparison.CurrentCultureIgnoreCase)) continue;
if (index == foundIndex) return reader[i];
foundIndex++;
}
return false;
}
}
}
Use it thus:
var value1 = reader.NamedValue("duplicatedColumnName", 0);
var value2 = reader.NamedValue("duplicatedColumnName", 1);