How can I distinct a complex object list in DART - list

I have one list of complex object. How can I distinct the list using their IDs?
I cant use toSet and similars, because the hashcode from the objects all are diferent.

1) Vanilla Dart
Loop through the list, adding IDs to a set as you go. Whenever you add an ID to the set that didn't already exist, add that element to a new list of distinct values.
void main() {
var list = [
Data('a'),
Data('a'),
Data('b'),
Data('c'),
];
var idSet = <String>{};
var distinct = <Data>[];
for (var d in list) {
if (idSet.add(d.id)) {
distinct.add(d);
}
}
}
class Data {
Data(this.id);
final String id;
}
2) Packages
Several packages exist that expand on default the Iterable utility methods, such as flinq or darq. They add a distinct method you can call to easily get a list of unique members of a list based on some property of the members.
import 'package:darq/darq.dart';
void main() {
var list = [
Data('a'),
Data('a'),
Data('b'),
Data('c'),
];
var distinct = list.distinct((d) => d.id).toList();
}
(Disclaimer, I am the maintainer of darq.)

Try to use this extension:
extension IterableExtension<T> on Iterable<T> {
Iterable<T> distinctBy(Object getCompareValue(T e)) {
var result = <T>[];
this.forEach((element) {
if (!result.any((x) => getCompareValue(x) == getCompareValue(element)))
result.add(element);
});
return result;
}
}
Using:
var distinctList = someList.distinctBy((x) => x.oid);
Or you can use a hash there.

Related

How to convert or equalize Query<Map<String, dynamic>> to List

I have BrandList in my Firebase like this;
How can I convert or equalize this Firebase List to List.
I tried this;
var brandsRef = _firestore.collection("vehicles1").where("Brands");
List brandsList = brandsRef;
But I got this error "A value of type 'Query<Map<String, dynamic>>' can't be assigned to a variable of type 'List'."
You need to use the document Id to get the query and then you can get the data which returns a Map.
From that Map, you can supply the key to retrieve the value. In this case, the key is "Brands".
var brandsQuery = await _firestore.collection("vehicles1").doc(document Id).get();
List brandList = brandsQuery.data()["Brands"];
First I would suggest to create a model of your class Brand in addition to the jsonSerialization classics:
class Brands {
Brands({this.brandName});
List<String> brandName;
Map<String, dynamic> toMap() {
return {
'Brands': brandName,
};
}
factory Brands.fromMap(Map<String, dynamic> map) {
return Brands(
brandName: List<String>.from(map['Brands']),
);
}
String toJson() => json.encode(toMap());
factory Brands.fromJson(String source) => Brands.fromMap(json.decode(source));
}
Then you need to add a few steps to the way you retreive elements:
var response = _firestore.collection("vehicles1").where("Brands").get();
final results =
List<Map<String, dynamic>>.from(response.docs.map((e) => e.data()));
Brands brands =
results.map((e) => Brands.fromMap(e)).toList();

How to add elements dynamically in a 2d list from another list in Flutter?

I have a list of model class objects. Such as -
List<ModelChannel> allChannels = [];
I have added elements in this list from json. Model Class variables are-
final String channelid;
final String channelname;
final String channeltype;
final String categoryname;
final String channelimage;
final String channelurl;
Here categorytype contains country information. I want to divide the list country wise dynamically. I have intended to use 2d list where each row will contain all the channels of a specific country. Is this the right approach? If yes how to implement this and if not what will be the right one?
If I understand correctly, you are looking for groupBy function from collection package.
Add this package to your pubspec.yaml:
dependencies:
collection: any
And use groupBy:
import 'package:collection/collection.dart';
...
final groupByCountry = groupBy(allChannels, (ModelChannel e) => e.categoryname);
List<List<ModelChannel>> countryList = [];
List<String> channelType = [];
allChannels.forEach((element) {
if (channelType.isEmpty) {
channelType.add(element.channeltype);
} else {
if (channelType.contains(element.channeltype)) {
} else {
channelType.add(element.channeltype);
}
}
});
channelType.forEach((countryCode) {
List<ModelChannel> t = [];
allChannels.forEach((element) {
if (element.channeltype == countryCode) {
t.add(element);
}
});
countryList.add(t);
});

Microsoft.SharePoint.Client C# getting only User created Lists (and not Document Libraries)

I am trying to retrieve a list of user generated Lists from a specified website. I do not want System generated lists (eg MicroFeed) nor Document Libraries. Using the Microsoft example I have this code:
public static void LoadLists(Microsoft.SharePoint.Client.Web web, List<String> foldersList)
{
var ctx = web.Context;
ListCollection collList = web.Lists;
IEnumerable<List> listInfo = ctx.LoadQuery(
collList.Include(
list => list.Title,
list => list.Fields.Include(
field => field.Title,
field => field.InternalName)));
ctx.ExecuteQuery();
foreach (List oList in listInfo)
{
FieldCollection collField = oList.Fields;
foreach (Microsoft.SharePoint.Client.Field oField in collField)
{
Regex regEx = new Regex("name", RegexOptions.IgnoreCase);
if (regEx.IsMatch(oField.InternalName))
{
Console.WriteLine("List: {0} \n\t Field Title: {1} \n\t Field Internal Name: {2}",
oList.Title, oField.Title, oField.InternalName);
}
}
}
}
However this returns all Lists and Document Libraries (and heaven knows what else). Is there an easy way to just get back the user defined lists? Here is an example of what I would like to get:
And looking at the documentation from Microsoft they seems to use the term list to refer to actual lists (tables) and document libraries (folders). What is the proper nomenclature for getting the list that is really just like an excel spreadsheet of data? Finally, is it possible for lists (tables) to be nested in side a Document Libraries? I can't seem to be able to do this, but I wanted to check since I am new to SharePoint.
Thanks!
So after having to lookup lots of examples (not from Microsoft, thank you) and stepping thru actual responses, here is the code for loading only the Lists and their field columns (not hidden) created by the user. I am sure that this could be optimized/cleaned up (for example not having to run the secondary queries to get List attributes, but it gave me access denied in original query), but it is working for me. Also needs some loving care for try-catches in case things go south.
First a couple of classes to hold the data:
public class SharePointColumn
{
public string Title { get; set; }
public string InternalName { get; set; }
public string TypeAsString { get; set; }
}
public class SharePointLibrary
{
public SharePointLibrary()
{
Columns = new List<SharePointColumn>();
}
public string Title { get; set; }
public Boolean IsList { get; set; } // If true a list, else DocumentLibrary
public List<SharePointColumn> Columns { get; set; }
}
Then the real code.
public static void LoadLists(Microsoft.SharePoint.Client.Web web, List<SharePointLibrary> sharePointLibraries)
{
var ctx = web.Context;
ListCollection collList = web.Lists;
IEnumerable<List> listInfo = ctx.LoadQuery(
collList.Include(
list => list.Title,
list => list.Fields.Include(
field => field.Title,
field => field.InternalName,
field => field.Hidden,
field => field.TypeAsString)));
ctx.ExecuteQuery();
foreach (List oList in listInfo)
{
// Had to add these because trying to add in above query failed
ctx.Load(oList);
ctx.ExecuteQuery();
// 544 Base Template is MicroFeed
if (oList.Hidden == false && oList.IsCatalog == false && (!oList.IsObjectPropertyInstantiated("IsSiteAssetsLibrary") || oList.IsSiteAssetsLibrary == false) &&
oList.BaseType != BaseType.DocumentLibrary && oList.BaseTemplate != 544)
{
FieldCollection collField = oList.Fields;
SharePointLibrary lib = new SharePointLibrary
{
Title = oList.Title,
IsList = true,
Columns = new List<SharePointColumn>()
};
foreach (Microsoft.SharePoint.Client.Field oField in collField)
{
if (!oField.Hidden)
{
SharePointColumn col = new SharePointColumn();
col.Title = oField.Title;
col.InternalName = oField.InternalName;
col.TypeAsString = oField.TypeAsString;
lib.Columns.Add(col);
}
}
sharePointLibraries.Add(lib);
}
}
}

Ember.computed.sort property not updating

I've been cracking my head for the last several days, trying to understand what am I doing wrong.
I'm implementing an infrastructure of lists for my app, which can include paging/infinite scroll/filtering/grouping/etc. The implementation is based on extending controllers (not array controllers, I want to be Ember 2.0 safe), with a content array property that holds the data.
I'm using Ember.computed.sort for the sorting, and it's working, but i have a strange behavior when i try to change the sorter. the sortedContent is not updating within the displayContent, even though the sortingDefinitions definitions are updated.
This causes a weird behaviour that it will only sort if I sort it twice, as if the sorting was asynchronous.
I am using Ember 1.5 (but it also happens on 1.8)
(attaching a snippet of code explaining my problem)
sortingDefinitions: function(){
var sortBy = this.get('sortBy');
var sortOrder = this.get('sortOrder') || 'asc';
if (_.isArray(sortBy)) {
return sortBy;
}
else {
return (sortBy ? [sortBy + ':' + sortOrder] : []);
}
}.property('sortBy', 'sortOrder'),
sortedContent: Ember.computed.sort('content', 'sortingDefinitions'),
displayContent: function() {
var that = this;
var sortBy = this.get('sortBy');
var sortOrder = this.get('sortOrder');
var list = (sortBy ? this.get('sortedContent') : this.get('content'));
var itemsPerPage = this.get('itemsPerPage');
var currentPage = this.get('currentPage');
var listItemModel = this.get('listItemModel');
return list.filter(function(item, index, enumerable){
return ((index >= (currentPage * itemsPerPage)) && (index < ((currentPage + 1) * itemsPerPage)));
}).map(function(item) {
var listItemModel = that.get('listItemModel');
if (listItemModel) {
return listItemModel.create(item);
}
else {
return item;
}
});
}.property('content.length', 'sortBy', 'sortOrder', 'currentPage', 'itemsPerPage')
Edit:
fixed by adding another dependency to the displayContent (sortedContent.[]):
displayContent: function() {
....
}.property('content.length', 'sortBy', 'sortOrder', 'currentPage', 'itemsPerPage' , 'sortedContent.[]')
Your sort function is watching the whole array sortingDefinitions instead of each element in the array. If the array changed to a string or some other variable it would update but not if an element in the array changes.
To ensure your computed property updates correctly, add a .[] to the end of the array so it looks like this: Ember.computed.sort('content', 'sortingDefinitions.[]')

Kotlin - List within a List filtering

I have those data classes:
data class RouteType(
#SerializedName("type")
val type: String,
#SerializedName("items")
val items: List<RouteItem>)
data class RouteItem(
#SerializedName("id")
val id: String,
#SerializedName("route")
private val route: List<DoubleArray>)
I want to filter list of RouteType by type and filter list of RouteItem in it by id.
My code now:
// val filter: HashMap<String, List<String>>
val result = routeTypes // List<RouteType>
.filter { it.type in filter.keys }
.map {
routeType -> routeType.items.filter { it.id in filter[routeType.type]!! }
}
How to make .map return list with filtered list in it? Or maybe there's another way?
EDIT
Thanks, but flatmap not exactly what I need, I think. flatmap returns nested list(List<RouteItem>), but I want List<RouteType>.
I got it by this code:
val result = routeTypes
.filter { it.type in filter.keys }
.map {
routeType -> RouteType(
routeType.type,
routeType.items.filter { it.id in filter[routeType.type]!! })
}
Is there another way to get it?
Since your data is immutable (that's a good thing) you need to copy it while filtering. Use copy to make it more extensible:
val result = routeTypes
.filter { it.type in filter.keys }
.map { it.copy(items = it.items.filter { it.id in filter[routeType.type]!! }) }
You can use flatMap for this, it works as map, but merges all your mapped collections to one:
val result = routeTypes // List<RouteType>
.filter { it.type in filter.keys }
.flatMap {
routeType -> routeType.items.filter { it.id in filter[routeType.type]!! }
}