I am getting back information from a websocket that might contain one or more items on each response.
I want to convert these responses to a list of custom objects.
The issue I have is where I want to use the first index (key) and second index (value) of the returned data and use them to pass into the custom object initialization to instantiate them and add them to the list.
I also want to add to the list, but if the 'name' field in an object already exists then just update that objects amount value instead of adding another copy. I will just do this with a loop, unless there is a shorter way.
Below you can see some of the attempts I have tried.
EDIT:
var listAmounts = valueMap.values.toList();
var listNames = valueMap.keys.toList();
print(listAmounts[0]);
print(listNames[0]);
for (int i = 0; i < listAmounts.length; i++) {
Person newPerson =
new Person(name: listNames[i], amount: double.parse(listAmounts[i]));
coins.add(newPerson);
print('=========');
print(newPerson.name);
print(newPerson.amount.toString());
print('=========');
}
I am not sure this is a good way as would there be a possibility that the keys/values will not be in order? From testing they are but I am not 100% sure?
Here are two examples of the message received from the websocket:
example 1
{jacob: 123.456789, steven: 47.3476543}
example 2
{henry: 54.3768574}
I have a custom class:
class Person {
double amount;
String name;
Person({
this.name = '',
this.amount = 0.0,
});
}
Here is the main code:
IOWebSocketChannel channel;
List<Person> people = [];
void openChannel() async {
channel = IOWebSocketChannel.connect(
"wss://ws.example.com/example?example=exp1,exp2,exp3");
channel.stream.listen((message) {
//print(message);
Map valueMap = json.decode(message);
print(valueMap);
//people = List<Person>.from(valueMap.map((i) => Person.fromJson(i)));
//message.forEach((name, amount) => people.add(Person(name: name, amount: amount)));
});
}
var listAmounts = valueMap.values.toList();
var listNames = valueMap.keys.toList();
print(listAmounts[0]);
print(listNames[0]);
for (int i = 0; i < listAmounts.length; i++) {
Person newPerson =
new Person(name: listNames[i], amount: double.parse(listAmounts[i]));
coins.add(newPerson);
print('=========');
print(newPerson.name);
print(newPerson.amount.toString());
print('=========');
}
Related
Good morning. I am building simple workout app in Flutter. I want to generate list of custom class Excersise:
class Excersise{
int id;
String name;
int duration;
int type;
Excersise({
required this.id,
required this.duration,
required this.name,
required this.type,
});
I want to pass parameter rounds, wtime(workout time) and ctime(cooldown time) from parent widget and then my app should create list of excersises. It should be pairs of workout and cool down time like this: wo 30sec, cd 15sec, wo 30sec, cd 15sec and so one (based on rounds value). I tried to generate this list via GET but after building this widget i get Stack overflow error. Maybe there is some error in code, maybe this is completely wrong method. Here is a code and thank for your advices.
class QuickWorkoutList extends StatelessWidget {
final int rounds;
final int wtime;
final int ctime;
QuickWorkoutList({
required this.rounds,
required this.wtime,
required this.ctime,
});
List<Excersise> get _qList {
var newEx = Excersise(id: 0, duration: 0, name: '', type: 0);
for (var i = 0; i < rounds * 2; i++) {
if (i.isEven) {
newEx.id = i;
newEx.name = 'Workout';
newEx.type = 0;
newEx.duration = wtime;
} else {
newEx.id = i;
newEx.name = 'Cooldown';
newEx.type = 1;
newEx.duration = ctime;
}
_qList.add(newEx);
}
throw 'No data';
}
Your getter method _qList is wrong implemented. You should create an empty List<Excersise> and add the Workout and Cooldown there. Currently you are recursively calling your _qList which has no anchor to stop. Consequently you have an endless loop. Btw I think you mean Exercise instead of Excersise.
List<Exercise> get _qList {
// All exercises stored
final List<Exercise> exercises = [];
// Exercise properties
int duration;
String name;
int type;
for (int i = 0; i < rounds * 2; i++) {
// Get exercise properties depending on id
if (i.isEven) {
name = 'Workout';
type = 0;
duration = wtime;
} else {
name = 'Cooldown';
type = 1;
duration = ctime;
}
// Add new exercise to list
exercises.add(
Excersise(
id: i,
duration: duration,
name: name,
type: type,
),
);
}
return exercises;
}
You shouldn't call add on your _qList getter, and that creates stack overflow I guess. You should use new List and return it from your _qList getter like this:
List<Excersise> get _qList {
var newEx = Excersise(id: 0, duration: 0, name: '', type: 0);
List<Excersise> exercises = [];
for (var i = 0; i < rounds * 2; i++) {
if (i.isEven) {
newEx.id = i;
newEx.name = 'Workout';
newEx.type = 0;
newEx.duration = wtime;
} else {
newEx.id = i;
newEx.name = 'Cooldown';
newEx.type = 1;
newEx.duration = ctime;
}
exercises.add(newEx);
}
return exercises;
}
i have one List (growable) with an item (actually item 0:
items is of class Team
items[_id = 1, _team = "Team01", _note = "blabla"]
and I want to transfer it into another list with a different structure:
participants is of class User
participants[id = 1, name = "participant1"]
skipping the note and translating _id into id and so on.So at last the result would give me
participants[id = 1, name = "team01"]
(sorry for the writing, I describe it out of the debugger)
i tried something like this, but doesnt work with value:
List<TestTeam> participants;
for (var value in items) {
participants.add(new TestTeam(value.id, value.team));
}
my class Team is defined like this:
class Team {
int _id;
String _team;
String _note;
Team(this._team, this._note);
Team.map(dynamic obj) {
this._id = obj['id'];
this._team = obj['team'];
this._note = obj['note'];
}
int get id => _id;
String get team => _team;
String get note => _note;
Map<String, dynamic> toMap() {
var map = new Map<String, dynamic>();
if (_id != null) {
map['id'] = _id;
}
map['team'] = _team;
map['note'] = _note;
return map;
}
Team.fromMap(Map<String, dynamic> map) {
this._id = map['id'];
this._team = map['team'];
this._note = map['note'];
}
}
You should implement below way
void main() {
List<Team> teams=[];
List<User> participants=[];
for (var i = 0; i < 4; i++) {
teams.add(Team(i,'Team_$i','Note_$i'));
}
for (var value in teams){
participants.add(User(value.id,value.team));
}
for (var value in teams){
print(value.toString());
}
for (var value in participants){
print(value.toString());
}
}
class Team{
int id;
String team;
String note;
Team(this.id,this.team,this.note);
toString()=> 'Team Map :{id:$id,team:$team,note:$note}';
}
class User{
int id;
String team;
User(this.id,this.team);
toString()=> 'User Map :{id:$id,team:$team}';
}
Output
Team Map :{id:0,team:Team_0,note:Note_0}
Team Map :{id:1,team:Team_1,note:Note_1}
Team Map :{id:2,team:Team_2,note:Note_2}
Team Map :{id:3,team:Team_3,note:Note_3}
User Map :{id:0,team:Team_0}
User Map :{id:1,team:Team_1}
User Map :{id:2,team:Team_2}
User Map :{id:3,team:Team_3}
I'm looking for the best approach to update an ObservableList with objects.
I've created a dummy example below with Car and a store with Cars.
In JavaScript I can simply call
const carData = {id: 1, name: "Chrysler"};
update(carData);
and in the update method:
#action
updateCar(carData) {
cars = cars.map(car => car.id === carData.id ? {...car, ...carData} : car);
}
How do one achieve the same in Flutter with MobX?
class Car {
int id;
String model;
DateTime year;
}
abstract class _CarCollectionStore with Store {
#observable
ObservableList<Car> cars = ObservableList<Car>();
#computed
get latestCar() => iterating and getting latest Car by year.
#action
updateCar(WHICH PARAMETERS?) {
...
}
}
How do I actually update the Name of the latestCar?
carCollectionStore = Provider.of<CarCollectionStore>(context, listen: false);
carNameController = TextEditingController(text: carCollectionStore.latestCar.name);
carNameController.addListener(() {
carCollectionStore.updateCar(carNameController.text);
});
The Plan:
So now what I basically want is to take my propertys out of the class, let the user pick some and then pull a List with ONLY those propertys out of MongoDB.
The Code:
here is where the method starts:
private void DoStuffExecute(object obj)
{
Class class= new Class();
ExtractClass(class);
if (propList != null)
{
var result = classService.DoStuff(propList);
}
}
in "ExtractClass()" the Propertys are being pulled out of the Class.
void ExtractClass(object obj)
{
foreach (var item in obj.GetType().GetProperties())
{
propList.Add(item.Name);
}
}
and finally in "classService.DoStuff()" i try to set the "fields".
public List<class> DoStuff(List<string> Props)
{
try
{
var filter = Builders<class>.Filter.Empty;
var fields = Builders<class>.Projection.Include(x => x.ID);
foreach (var item in Props)
{
string str = "x.";
str += item.ToString();
fields = Builders<class>.Projection.Include(x => str);
fields = Builders<class>.Projection.Include(x => item);
}
var result = MongoConnectionHandler.MongoCollection.Find(filter).Project<class>(fields).ToList();
return result;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
var result = new List<class>();
return result;
}
}
when i run the programm it gives me an "Unable to determine the serialization information for x=> value"... since im giving it a string.
The Question:
Does anyone have an Idea how to repair the code above or even make the plan work in another way?
thank you.
First of all: you are using such code lines as : var filter = Builders<class>.Filter.Empty; It is not possible, because class is a reserved keyword in c# (https://msdn.microsoft.com/en-us/library/x53a06bb.aspx) I assume, it's your Model, and i will speak about it as about Model class.
Include Filter needs Expression as a parameter, not a string, you should construct is as a expression. That's the second thing. Third, you should combine your includes as a chain, So your part of creating Include Filter from string List should look like:
var filter = Builders<Model>.Filter.Empty;
var fields = Builders<Model>.Projection.Include(x => x.Id);
foreach (var item in Props)
{
var par = Expression.Parameter(typeof(Model));
var prop = Expression.Property(par, item);
var cast = Expression.Convert(prop, typeof(object));
var lambda = Expression.Lambda(cast, par);
fields = fields.Include((Expression<Func<Model, object>>)lambda);
}
I have all expresiions separate for better understanding: first you create Parameter (x=>), than you add property (x=>x.Property1), than you should cast it to object, and after all create Lambda Expression from it.
And now the last part: You don't need all of it, Include function could get jsut a string as a parameter. So you could instead of all expression call write this:
fields = fields.Include(item);
I'm trying to get type fields for each attribute of my entities. Quering Orion and getting entities is not the problem (I do this through NGSI Source widget) but the way getting these parameters.
From NGSI Source (usual suscription to Orion instance):
var doInitialSubscription = function doInitialSubscription() {
this.subscriptionId = null;
this.ngsi_server = MashupPlatform.prefs.get('ngsi_server');
this.ngsi_proxy = MashupPlatform.prefs.get('ngsi_proxy');
this.connection = new NGSI.Connection(this.ngsi_server, {
ngsi_proxy_url: this.ngsi_proxy
});
var types = MashupPlatform.prefs.get('ngsi_entities').split(new RegExp(',\\s*'));
var entityIdList = [];
var entityId;
for (var i = 0; i < types.length; i++) {
entityId = {
id: '.*',
type: types[i],
isPattern: true
};
entityIdList.push(entityId);
}
var attributeList = null;
var duration = 'PT3H';
var throttling = null;
var notifyConditions = [{
'type': 'ONCHANGE',
'condValues': MashupPlatform.prefs.get('ngsi_update_attributes').split(new RegExp(',\\s*'))
}];
var options = {
flat: true,
onNotify: handlerReceiveEntity.bind(this),
onSuccess: function (data) {
this.subscriptionId = data.subscriptionId;
this.refresh_interval = setInterval(refreshNGSISubscription.bind(this), 1000 * 60 * 60 * 2); // each 2 hours
window.addEventListener("beforeunload", function () {
this.connection.cancelSubscription(this.subscriptionId);
}.bind(this));
}.bind(this)
};
this.connection.createSubscription(entityIdList, attributeList, duration, throttling, notifyConditions, options);
};
var handlerReceiveEntity = function handlerReceiveEntity(data) {
for (var entityId in data.elements) {
MashupPlatform.wiring.pushEvent("entityOutput", JSON.stringify(data.elements[entityId]));
}
};
To MyWidget:
MashupPlatform.wiring.registerCallback("entityInput", function (entityString) {
var entity;
entity = JSON.parse(entityString);
id = entity.id;
type = entity.type;
for(var attr in entity){
attribute = entity[attr];
}
I'm trying to code something similar to obtain the value of type fields. How can I do that? (I'm sure it's quite easy...)
You cannot make use of the current NGSI source operator implementation (at least v3.0.2) if you want to get the type metadata of attributes as the NGSI source makes use of the flat option (discarding that info).
We are studying updating this operator to allow creating subscriptions without using the flat option. The main problem here is that other components expect the data provided by this operator being provided in the format returned when using the flat option. I will update this answer after analysing deeper the issue.