As in Dart you can combine several list items into one according to the following condition:
Given List<String> arr = ['2','3','b','*','4','5','6','-','3','4'];
Get arr = ['23','b','*','456','-','34'];
The list is unknown in advance. It can be of any length and with any sequence of characters. And need to combine only the lines that have numbers in them.
I would be grateful for any suggestions.
You are not describing what should happen if there are multiple special characters or letters. So I have made my example so it will only combine numbers:
void main() {
final arr = ['2', '3', 'b', '*', '4', '5', '6', '-', '3', '4'];
print(combine(arr)); // [23, b, *, 456, -, 34]
}
List<String> combine(List<String> input) {
final output = <String>[];
final buffer = StringBuffer();
for (final string in input) {
if (int.tryParse(string) == null) {
if (buffer.isNotEmpty) {
output.add(buffer.toString());
buffer.clear();
}
output.add(string);
} else {
buffer.write(string);
}
}
if (buffer.isNotEmpty) {
output.add(buffer.toString());
}
return output;
}
You can use ''.join() here:
arr = [''.join(arr[0:2]), arr[2], arr[3], ''.join(arr[4:7]), arr[7], ''.join(arr[8:10])]
If you only want to have a condition where you only join numerical values then you can add a for loop beforehand.
Related
I have a list of elements and I need to get a list containing the first element followed by every nth element afterwards. For example: given n = 3 and the list [banana, cherry, apple, pear, kiwi], I need to get the list [banana, pear]. I need this regardless of specific content, since the list depends on user input.
How do I do this using Dart?
You may access list in dart by providing an index like for example:
List<String> fruits = ["banana","cherry","apple","pear","kiwi"];
print(fruits[0]); // Will print to the console "banana";
On your case, you are trying to access index 0 and index 3 which is "banana" and "pear".
You may create a function that accepts an index like:
String getFruit(int index, List<String> fruits) => fruits[index];
print(getFruit[0]); // Will print "banana";
or if you need to actually get the specific ranges you may use:
List<String> fruits =["banana","cherry","apple","pear","kiwi"].getRange(0,4);
// Will give you "banana","cherry","apple","pear
You may check : https://api.dart.dev/be/180791/dart-core/List-class.html for more information.
Edited answer based off the comment:
List<String> getElements(List userInput, nIndex){
List elements = [];
for(int x = 0; x<userInput.length;x++){
if(x % nIndex == 0){
elements.add(userInput[x]);
}
}
return elements;
}
List fruits = ["banana","cherry","apple","pear","kiwi"];
print(getElements(fruits,2));
or you may try to look and use List.retainWhere() depending on your use case.
Dart has a great set of collection operators that make this type of problem pretty straightforward to solve. For example, we could do something like:
extension X<T> on List<T> {
List<T> everyNth(int n) => [for (var i = 0; i < this.length; i += n) this[i]];
}
main() {
final fruit = ["banana", "cherry", "apple", "pear", "kiwi"];
print(fruit.everyNth(3));
}
Output:
[banana, pear]
You can use this extension method, which will work on lists of any type:
extension GetEveryN<T> on List<T> {
List<T> elementsEveryN(int n) {
List<T> result = [];
for(int index = 0; index < length; index +=1) {
if(index % n == 0) {
result.add(this[index]);
}
}
return result;
}
}
Trying it in an example:
List<String> list = ["banana", "cherry","apple", "pear","kiwi"];
print(list.elementsEveryN(2)); // [banana, pear]
I'm trying to fetch the randomly specific number of items from one list and add them to the other list but without duplication.
For example: pick three random items from the list randomly and put them into another list. This is what I have achieved so far but this could pick the duplicate item again.
List itemList = ['NAME1', 'NAME2', 'NAME3', 'NAME4', 'NAME3', 'NAME5', 'NAME2'];
List randomItems = [];
for(var i=0; i<=2; i++){ // run the loop for three times
int randomNumber = Random().nextInt(itemList.length); //generate random number within itemList range
randomItems.add(itemList[randomNumber]); // duplication occur, for example: NAME2 could be added two times
}
There are several steps we can do to solve this problem. First, we want to get rid of the duplicate elements in the list. We can here do that by converting the list to a Set:
List<String> itemList = [
'NAME1',
'NAME2',
'NAME3',
'NAME4',
'NAME3',
'NAME5',
'NAME2'
];
Set<String> itemSet = itemList.toSet();
print(itemSet); // {NAME1, NAME2, NAME3, NAME4, NAME5}
Then, we want to extract 3 random elements from this new Set in such a way that we can't select the same element twice. The easiest way to solve this is by shuffle the elements randomly and then take elements from our collection. But Set does not have the concept of any specific "order" and we can't therefore shuffle our Set.
So let's convert our Set back to a List:
Set<String> itemSet = itemList.toSet();
List<String> itemListFromSet = itemSet.toList();
print(itemListFromSet); // [NAME1, NAME2, NAME3, NAME4, NAME5]
We can then shuffle this new list:
itemListFromSet.shuffle();
print(itemListFromSet); // [NAME3, NAME2, NAME4, NAME5, NAME1]
If we then want 3 random selected elements, we can just take 3 elements from this randomly ordered list. So e.g. (take returns an iterable which we then makes a new list of):
List<String> randomItems = itemListFromSet.take(3).toList();
A complete solution would look like:
void main() {
List<String> itemList = [
'NAME1',
'NAME2',
'NAME3',
'NAME4',
'NAME3',
'NAME5',
'NAME2'
];
Set<String> itemSet = itemList.toSet();
List<String> itemListFromSet = itemSet.toList();
itemListFromSet.shuffle();
List<String> randomItems = itemListFromSet.take(3).toList();
print(randomItems); // [NAME5, NAME2, NAME4]
}
Which can be reduced down to:
void main() {
List<String> itemList = [
'NAME1',
'NAME2',
'NAME3',
'NAME4',
'NAME3',
'NAME5',
'NAME2'
];
List<String> randomItems =
(itemList.toSet().toList()..shuffle()).take(3).toList();
print(randomItems); // [NAME3, NAME4, NAME2]
}
I have a dart list:
List<String?> vals;
I want to remove any null values and convert it to a List<String>.
I've tried:
List<String> removeNulls(List<String?> list) {
return list.where((c) => c != null).toList() as List<String>;
}
At run time I'm getting the following error:
List<String?>' is not a subtype of type 'List<String>?'
What is the correct way to resolve this?
Ideally you'd start with a List<String> in the first place. If you're building your list like:
String? s = maybeNullString();
var list = <String?>[
'foo',
'bar',
someCondition ? 'baz' : null,
s,
];
then you instead can use collection-if to avoid inserting null elements:
String? s = maybeNullString();
var list = <String?>[
'foo',
'bar',
if (someCondition) 'baz',
if (s != null) s,
];
An easy way to filter out null values from an Iterable<T?> and get an Iterable<T> result is to use .whereType<T>(). For example:
var list = <String?>['foo', 'bar', null, 'baz', null];
var withoutNulls = list.whereType<String>().toList();
Another approach is to use collection-for with collection-if:
var list = <String?>['foo', 'bar', null, 'baz', null];
var withoutNulls = <String>[
for (var s in list)
if (s != null) s
];
Finally, if you already know that your List doesn't contain any null elements but just need to cast the elements to a non-nullable type, other options are to use List.from:
var list = <String?>['foo', 'bar', 'baz'];
var withoutNulls = List<String>.from(list);
or if you don't want to create a new List, Iterable.cast:
var list = <String?>['foo', 'bar', 'baz'];
var withoutNulls = list.cast<String>();
Without creating a new List
void main() {
List<String?> list = ['a', null, 'b', 'c', null];
list.removeWhere((e) => e == null); // <-- This is all you need.
print(list); // [a, b, c]
}
Creating a new List
First create a method, filter for example:
List<String> filter(List<String?> input) {
input.removeWhere((e) => e == null);
return List<String>.from(input);
}
You can now use it:
void main() {
List<String?> list = ['a', null, 'b', 'c', null];
List<String> filteredList = filter(list); // New list
print(filteredList); // [a, b, c]
}
To use retainWhere, replace the predicate in removeWhere with (e) => e != null
I want to generate INSERT statement from JSON. The problem that I have problem with recursion (in section where I am getting nested elements). it's seems that I am getting SO.
import 'dart:convert';
main() {
Map jsonMap = jsonDecode(
'{"id":"1","name":"sample","Lots":[{"id":"1","title":"books","objs":[{"book":"name"}]}]}');
KVToTableInsert(String tablename, Map jsonMap) {
List<String> insertNoticeKeys = [];
List<String> insertNoticeValues = [];
jsonMap.forEach((key, value) {
if (value is List) // nested
{
KVToTableInsert(key, jsonMap); // if comment this line all work
} else {
insertNoticeKeys.add(key);
insertNoticeValues.add(value);
}
});
String sql = "INSERT INTO $tablename (" +
insertNoticeKeys.map((e) => '"$e"').join(', ') +
") VALUES (" +
insertNoticeValues.map((e) => "'$e'").join(', ') +
")";
print(sql);
}
KVToTableInsert("RootTable", jsonMap);
}
I expected to get 3 INSERT statment:
INSERT INTO RootTable ("id", "name") VALUES ('1', 'sample')
INSERT INTO Lots ("id", "title") VALUES ('1', 'books')
INSERT INTO Objs ("book") VALUES ('name')
But I am getting crush on this app.
There was a slight problem in your code, basically in this part:
if (value is List){
KVToTableInsert(key, jsonMap); // if comment this line all work
}
If you closely, take a look at your KVToTableInsert, you're passing arguments Map and not list. Which fails your recursion.
What you need to do is to pass the item of the array, into your KVToTableInsert, and this will work as expected
FINAL SOLUTION
// taking your jsonMap directly, and not decoding it
void main() {
Map jsonMap = {
"id":"1",
"name":"sample",
"Lots":[
{
"id": "1",
"title":"books",
"objs":[
{
"book":"name"
}
]
}
]
};
void KVToTableInsert(tablename, jsonMap){
List<String> insertNoticeKeys = [];
List<String> insertNoticeValues = [];
jsonMap.forEach((key,value){
if (value is List)
{
// Here is the magic, you need to iterate over your list, and pass MAP, not LIST
value.forEach((item){ KVToTableInsert(key, item);});
} else {
insertNoticeKeys.add(key);
insertNoticeValues.add(value);
}
});
String sql = "INSERT INTO $tablename (" +
insertNoticeKeys.map((e) => '"$e"').join(', ') +
") VALUES (" +
insertNoticeValues.map((e) => "'$e'").join(', ') +
")";
print(sql);
}
KVToTableInsert("Rootable", jsonMap);
}
OUTPUT
INSERT INTO objs ("book") VALUES ('name')
INSERT INTO Lots ("id", "title") VALUES ('1', 'books')
INSERT INTO Rootable ("id", "name") VALUES ('1', 'sample')
Also, look at the Dart Programming Language Naming Conventions, it is a good practise to use lowerCamelCase for your function/method name.
I have this map:
var temp= {
'A' : 3,
'B' : 1,
'C' : 2
};
How to sort the values of the map (descending). I know, I can use temp.values.toList()..sort().
But I want to sort in context of the keys like this:
var temp= {
'B' : 1,
'C' : 2
'A' : 3,
};
This example uses a custom compare function which makes sort() sort the keys by value. Then the keys and values are inserted into a LinkedHashMap because this kind of map guarantees to preserve the order.
Basically the same as https://stackoverflow.com/a/29629447/217408 but customized to your use case.
import 'dart:collection';
void main() {
var temp= {
'A' : 3,
'B' : 1,
'C' : 2
};
var sortedKeys = temp.keys.toList(growable:false)
..sort((k1, k2) => temp[k1].compareTo(temp[k2]));
LinkedHashMap sortedMap = new LinkedHashMap
.fromIterable(sortedKeys, key: (k) => k, value: (k) => temp[k]);
print(sortedMap);
}
Try it on DartPad
The SplayTreeMap has a named constructor which accepts map and a comparator which is used to sort given map while building new map. Since SplayTreeMap is a descendant of Map you can easily substitute it.
import 'dart:collection';
void main() {
var unsorted = {'A': 3, 'B': 1, 'C': 2};
final sorted = SplayTreeMap.from(
unsorted, (key1, key2) => unsorted[key1].compareTo(unsorted[key2]));
print(sorted);
}
final Map<String, ClassCategory> category;
...
Map<String, ClassCategory> sorted = SplayTreeMap.from(category,
(key1, key2) => category[key1]!.title.compareTo(category[key2]!.title));
for (var item in sorted.entries) {
...
}