I have an array of items that looks like this:
final List<Map<String, String>> dateIdeas = [
{'Description': 'Drink Cocktails','Image': 'assets/images/cocktailsfull.jpg'},
{'Description': 'Go for dinner!', 'Image': "assets/images/dinner.jpg"},
];
When the user taps a button the first item is removed from the array.
removeItem() {
setState(() {
dateIdeas.removeAt(index);
});
}
This works correctly. However, I want the user to be able to undo this action. My solution to this was to perform the following:
Have the removeItem function return what the array looked like before the removal:
Map<String, String> removeItemLiked() {
final removed = dateIdeas[index];
setState(() {
_controller.reset();
likes.add(dateIdeas[index]['Description']);
dateIdeas.removeAt(index);
});
return removed;
}
Have an undo function that adds the item back into the array at index 0:
void undo() {
setState(() {
Map<String, String> result = removeItemLiked();
dateIdeas.insert(0, result);
});
}
The issue here is that when triggering the undo function it also retriggers removeItem. How can I have the old array stored to a variable so I can always use it later on?
The removeItem is getting called by you within the undo function.
To prevent this, separate the function call from the removed variable.
// within stateful widget, declare 'removed'...
Map<String, String> removed;
Your other functions get modified like so;
void removeItemLiked() {
removed = dateIdeas[index];
setState(() {
_controller.reset();
likes.add(dateIdeas[index]['Description']);
dateIdeas.removeAt(index);
});
}
void undo() {
if(removed != null) {
setState(() {
dateIdeas.insert(0, removed);
});
}
}
You can store the removed item in a variable like lastRemoved and store it's index and value both. Here's a simple example:
class MyNums {
List<int> numbers = [123, 34, 5, 436, 56, 677];
Map<String, dynamic> lastRemoved;
removeItem(int index) {
lastRemoved = {
'index': index,
'item': numbers[index],
};
numbers.removeAt(index);
}
undoRemove() {
if (lastRemoved != null) {
numbers.insert(lastRemoved['index'], lastRemoved['item']);
}
lastRemoved = null;
}
}
Test:
main() {
MyNums nums = MyNums();
print('initial:\t\t ${nums.numbers}');
nums.removeItem(2);
print('remove from index 2:\t ${nums.numbers}');
nums.undoRemove();
print('undo index 2:\t\t ${nums.numbers}');
nums.removeItem(2);
print('remove from index 2:\t ${nums.numbers}');
nums.removeItem(2);
print('remove from index 2:\t ${nums.numbers}');
nums.undoRemove();
print('undo index 2:\t\t ${nums.numbers}');
nums.undoRemove();
print('nothing to undo:\t ${nums.numbers}');
}
Output:
initial: [123, 34, 5, 436, 56, 677]
remove from index 2: [123, 34, 436, 56, 677]
undo index 2: [123, 34, 5, 436, 56, 677]
remove from index 2: [123, 34, 436, 56, 677]
remove from index 2: [123, 34, 56, 677]
undo index 2: [123, 34, 436, 56, 677]
nothing to undo: [123, 34, 436, 56, 677]
Related
I have this list [null, 3, 5, null] and I want to join the values in-between nulls and put it into the same list
For example:
[null, 3, 5, null] into [null, 35, null]
I made this one extension that groups all the values between two nulls
extension GroupByNull<T> on List<T> {
List<List<T>> groupByNull() {
final groupedList = <List<T>>[];
var list = this;
for (var i = 0; i < list.length; i++) {
if (list[i] == null) {
if (i > 0) {
groupedList.add(list.sublist(0, i));
}
list = list.sublist(i + 1);
i = 0;
}
}
if (list.isNotEmpty) {
groupedList.add(list);
}
return groupedList;
}
}
Which returns [[3, 5]] for [null, 3, 5, null]... But I want it to be joined together and added to the original list in the same index
How can I solve this...
thank you.
Note that you can't operate on an arbitrary List<T> because there's no general way to combine two elements of some arbitrary type T. What you want could make sense for List<int?> or maybe List<String?>. (Or maybe it could work on an arbitrary List<T> input if you want a List<String?> output.)
Assuming that you want to operate on List<int?>, then basically as you iterate over your input list, keep track of your current accumulated value. If you encounter null, add the current value (if any) to your output List along with the null. Don't forget to add the current accumulated value (if any) when you're done iterating in case there isn't a final null element.
extension GroupByNull on List<int?> {
List<int?> groupByNull() {
var result = <int?>[];
int? currentValue;
for (var element in this) {
if (element != null) {
currentValue = (currentValue ?? 0) * 10 + element;
} else {
if (currentValue != null) {
result.add(currentValue);
currentValue = null;
}
result.add(currentValue);
}
}
if (currentValue != null) {
result.add(currentValue);
}
return result;
}
}
void main() {
print([null, 3, 5, null].groupByNull()); // Prints: [null, 35, null]
print([3, 5, null].groupByNull()); // Prints: [35, null]
print([3, 5, null, null].groupByNull()); // Prints: [35, null, null]
print([null, 3, 5].groupByNull()); // Prints: [null, 35]
print([null, null, 3, 5].groupByNull()); // Prints: [null, null, 35]
print([null, 0, 0, 0, null].groupByNull()); // Prints: [null, 0, null]
print([null, 1, 2, null, 3, 4, null]
.groupByNull()); // Prints: [null, 12, null, 34, null]
print([null].groupByNull()); // Prints: [null]
print([null, null].groupByNull()); // Prints: [null, null]}
}
You can use this solution.
extension GroupByNull<T> on List<T> {
List groupByNull() {
final groupedList = [];
var list = this;
list.removeWhere( (value) => value == null); // remove all null values
groupedList.add(int.parse(list.join(""))); // combine number left in list
groupedList.insert(0,null); // add null
groupedList.add(null);
return groupedList;
}
}
Actually, I'm trying to return a list from the 19th index, but this didn't work for me. This list is split into sub lists. I want to start splitting it from the 19th index not from 0.
This is my code:
static Future<List> local() async {
File textAsset = File('/storage/emulated/0/RPSApp/assets/bluetooth.txt');
final text = await textAsset.readAsString();
final bytes =
text.split(',').map((s) => s.trim()).map((s) => int.parse(s)).toList();
int chunkSize = 19;
List<int> padTo(List<int> input, int count) {
return [...input, ...List.filled(count - input.length, 255)];
}
List<int> padToChunksize(List<int> input) => padTo(input, chunkSize);
List<List<int>> items;
items = bytes.slices(chunkSize).map(padToChunksize).toList();
for (int i = 19; i < bytes.length; i++) {
return items;
}
return items;
}
this code is for displaying sublists one by one:
final chun = await Utils.local();
await Future.forEach(chun, (ch) async {
await Future.delayed(const Duration(seconds: 4));
await c.write(chun, withoutResponse: true);
await c.read();
await Future.wait(getValue());
}
})
I don't know what's wrong with this code and why it returns me the list from index 0.
Honestly its quite difficult to understand your code. since its mixed in 1 function.
its return from index 0 because:
items = bytes.slices(chunkSize).map(padToChunksize).toList();
and then you keep return items. which is return all items.
you have to create new list and cut the index based on you need.
Solutions:
ill answer based on list that you provide in comment section:
List data = [144, 9, 146, 8, 191, 0, 32, 0, 240, 84, 130, 16, 70, 79, 240, 0, 11, 170, 0, 0, 0, 242];
// method 1 ( recomended)
final newList = data.skip(19);
print(newList); // result: (0, 0, 242)
// method 2
final newlist2 = temp.getRange(19,data.length);
print(newlist2); // result: (0, 0, 242)
both method will return the list from index 19. choode which method do you like to use. i will recommend to use skip, since it will not throw error if the list length is less than 19
If you look at the code snipper below, you are returning complete list of input and another set of list with filled with 255 which is wrong.
List<int> padTo(List<int> input, int count) {
return [...input, ...List.filled(count - input.length, 255)];
}
If you want to return the list from index 19, then you need to correct the code snippet as below.
List<int> padTo(List<int> input, int count) {
return [...input.skip(19), ...List.filled(count - input.length, 255)];
}
This will skip the first 19 elements in the input list, but you must understand that the input of length is more than 19 otherwise, it will return a empty list.
I have a Map that contains a List and I want to get a specific value.
Here is the map.
Map res ={65535: [198, 28, 231, 228, 87, 210, 255, 0, 57, 30, 14]} ;
I want to get to the value 57,
any help ?
You can follow the snippet where element will find from values and provide key and element index.
Map<int, List<int>> res = {
65535: [198, 28, 231, 228, 87, 210, 255, 0, 57, 30, 14]
};
// while everything is int here
final int findElement = 57;
int? keyOf57;
int? indexOf57;
res.forEach((key, value) {
if (value.contains(findElement)) {
keyOf57 = key;
indexOf57 = value.indexOf(findElement);
return;
}
});
/// also check if `indexOf57` is null or not
print("key:$keyOf57 index:$indexOf57 value ${res[keyOf57]?[indexOf57??0]}");
May I split List date the put into for loop or use switch case??
this is my code
getFeature() async {
final docSnapshot = await FirebaseFirestore.instance
.collection('Campsite')
.doc(widget.CamperSiteID)
.get();
final CamperSiteSummary =
List<int>.from(docSnapshot.data()?['CamperSiteSummary'] ?? []);
//this._CamperSiteSummary.addAll(CamperSiteSummary);
setState(() {
_CamperSiteSummary = CamperSiteSummary;
print(_CamperSiteSummary);
});
}
I'd print the data
flutter: [2, 3, 5, 6, 10, 13, 14, 19, 29, 37]
So, May I split _CamperSiteSummary data then put into loop or use switch case??
I hope it's can realize this, this is my android(JAVA) screen.
So, I need to split the data then how could used loop way to show image?
this is my android-jave code
public void showChips(ChipGroup chipGroup, List<Integer> chipList) {
HashMap<Integer, Integer> campSiteMap = new HashMap<>();
campSiteMap.put(1, R.id.chip1);
campSiteMap.put(2, R.id.chip2);
campSiteMap.put(3, R.id.chip3);
campSiteMap.put(4, R.id.chip4);
campSiteMap.put(5, R.id.chip5);
...
...
...
campSiteMap.put(37, R.id.chip37);
campSiteMap.put(38, R.id.chip38);
campSiteMap.put(39, R.id.chip39);
try {
for (Integer id : chipList){
chipGroup.findViewById(campSiteMap.get(id)).setVisibility(View.VISIBLE);
}
} catch (Exception e) {
// TODO: get no id
}
}
How can modity fluute code?
When I use https://dartpad.dev/?id
import 'package:intl/intl.dart';
void main() {
final matches = [
{
"match_id": 6604501658,
"player_slot": 129,
"radiant_win": false,
"duration": 2020,
"game_mode": 22,
"lobby_type": 7,
"hero_id": 19,
"start_time": 1654520510,
"version": 21,
"kills": 13,
"deaths": 7,
"assists": 17,
"skill": null,
"xp_per_min": 780,
"gold_per_min": 604,
"hero_damage": 36271,
"tower_damage": 10042,
"hero_healing": 0,
"last_hits": 211,
"lane": 2,
"lane_role": 2,
"is_roaming": false,
"cluster": 156,
"leaver_status": 0,
"party_size": 1
},
{
"match_id": 6604451816,
"player_slot": 4,
"radiant_win": false,
"duration": 1242,
"game_mode": 22,
"lobby_type": 7,
"hero_id": 52,
"start_time": 1654518740,
"version": 21,
"kills": 7,
"deaths": 4,
"assists": 1,
"skill": null,
"xp_per_min": 540,
"gold_per_min": 472,
"hero_damage": 14678,
"tower_damage": 2111,
"hero_healing": 0,
"last_hits": 136,
"lane": 2,
"lane_role": 2,
"is_roaming": false,
"cluster": 156,
"leaver_status": 0,
"party_size": 1
}
];
final List<String> extraList = ['kills','deaths','assists','gold_per_min','xp_per_min','last_hits','hero_damage','hero_healing','tower_damage','duration'];
for(var i in extraList) {
print(averMax(matches, i));
}
}
String averMax(dynamic matches, String field) {
final dynamic matchesMap = matches.map((match) => match[field]);
final dynamic matchesReduce = matchesMap.reduce((cur, total) => cur + total);
return field != 'duration' ?
greaterNum((matchesReduce / 20).round(), 1000, 'K') :
(matchesReduce / 20).toString();
}
String greaterNum(double num, int gN, String unit) {
var minus = '';
if (num < 0) {
minus = '-';
}
num = (num).abs();
if (num > gN) {
final newNum = (num / gN).toStringAsFixed(1);
return '$minus$newNum$unit';
} else {
return '$minus$num';
}
}
Works
However at flutter:
Flutter the PlayerMatches is from API which is List
I want to map the extraList value as key in the matches to dynamic get data and pass to a List View
In dartPad works, however in flutter cant access data use square brackets.
My question:
Could I access the Object key dynamically like javascript?
Thanks for #lepsch who help me
At flutter,
return match.toJson()[field];
Flutter doesn't support reflection/mirrors so it's not possible to get a property by name. This is on purpose so Flutter knows at compile time all kinds of access to an object that exists and can optimize it accordingly by tree-shaking (Strip out anything that isn’t used).
One solution could be converting PlayerRecentMatch to JSON as a Map<String, dynamic>. This way you can access the Map with the brackets operator.
Another way though to implement your function is using a first-class function as an argument to get the property instead of the property name. Take a look below:
class PlayerRecentMatch {
final double score;
const PlayerRecentMatch({required this.score});
}
double averMax(
List<PlayerRecentMatch> matches,
double Function(PlayerRecentMatch) getProperty, // <- Here
) {
final matchesMap = matches.map((match) {
return getProperty(match);
}).toList();
final matchesReduce = matchesMap.reduce((sum, total) => sum + total);
return matchesReduce / matches.length;
}
void main() {
final matches = [
PlayerRecentMatch(score: 1),
PlayerRecentMatch(score: 2),
PlayerRecentMatch(score: 3),
PlayerRecentMatch(score: 4),
];
print('averMax = ${averMax(matches, (match) => match.score)}');
}
https://dartpad.dev/?id=44cbecffd6f86f1714a4553101a16001