Dart custom sorting of a list - sorting

I want to build a suggestion builder where I want to display search suggestions on changing the text in TextField. I want to search on the basis of contains method but I want to sort that particular list on the basis of startsWith, If I only use startsWith it neglects all other contains, How can I apply both simultaneously?
I have a List,
List<String> list = ["apple", "orange", "aaaaorange", "bbbborange","cccccorange"]
Now If I put only ora in search it's returning me in the following order,
aaaaorange
bbbborange
cccccorange
orange
What I want.
orange
aaaaorange
bbbborange
cccccorange
Code:
return list
.where((item) {
return item.toLowerCase().contains(query.toLowerCase());
}).toList(growable: false)
..sort((a, b) {
return a.toLowerCase().compareTo(b.toLowerCase());
});

It may be easiest to think of the two queries separately, and then combine the results:
var list = <String>[
'apple',
'orange',
'aaaaorange',
'bbbborange',
'cccccorange',
];
var pattern = 'ora';
var starts = list.where((s) => s.startsWith(pattern)).toList();
var contains = list
.where((s) => s.contains(pattern) && !s.startsWith(pattern))
.toList()
..sort((a, b) => a.toLowerCase().compareTo(b.toLowerCase()));
var combined = [...starts, ...contains];
print(combined);

Related

How to search for substring in a list of strings in episerver find

I have a list of strings like this
"Users": [
"usrName|Fullname|False|0|False|False",
"usrName|Fullname|False|0|False|False",
"usrName|Fullname|False|0|False|False",
"usrName|Fullname|False|0|False|False",
"usrName|Fullname|False|0|False|False",
]
In my episerver/optimizely code I want to match items. I have written this line of code
searchResult.Filter(x => x.Users.MatchContained(k=> k.Split('|')[3], "0"));
I am trying to get all Users where after splitiing on 'pipe' I get 0 at index 3. I am not getting the result, infact I get an exception.
What am I doing wrong here?
Since you left out A LOT of details these are my assumptions
Users is an IList<string> Users
You are trying to get all Users within that list/array where index 3 equals 0
What we don't know is, among others
Is there more than one page instance that have the Users instance filled?
Anyway, this cannot be solved using any Find API with the current system design. Instead you need to rely on linq to parse the result, but then the Find implementation may not be necessary.
var searchClient = SearchClient.Instance;
var search = searchClient.Search<BlogPage>();
var result = search.GetContentResult();
var usersResult = result
.SelectMany(x => x.Users)
.Where(x => x.Split('|')[3].Equals("0"));
This would create and return an object similar to this, since I'm using SelectMany the array would contain all users throughout the systems where there are matched pages from the search result.
If you for whatever reason would like to keep or see some page properties there are alternative approaches where you construct a new object within a select and remove any object where there where not matched users
var searchClient = SearchClient.Instance;
var search = searchClient.Search<BlogPage>();
var result = search.GetContentResult();
var usersResult = result
.Select(p => new
{
PageName = p.Name,
ContentLink = p.ContentLink.ToString(),
Users = p.Users.Where(x => x.Split('|')[3].Equals("0"))
})
.Where(x => x.Users.Any());
If you like to keep using Find for this kind of implementations you must store the data in a better way than strings with delimiters.

linq select items where property of items in list not in properties of items in another list

I have two lists of 2 different types of classes. I want to select all of the items in the first list that have a property (we'll call it name) that do not have coresponding objects with same name in another list.
For example if I have a list of Age items (joe, 4), (marry,5), (ed,2)
and another list of relation items (joe,father), (ed,brother)
I want to end up with a resulting list of (marry,5)
I was not sure if "except" was somehow used here.
Given two arrays (I'm using anonymous types here, but it's the same deal with proper classes) of different types, you're going to need to extract the excepted 'key' first. In this case the 'key' is the Name property.
//Setup
var ageItems = new [] { new {Name = "Joe", Age=4}, new {Name = "Marry", Age=5}, new {Name="Ed", Age=2} };
var relationItems = new [] { new {Name="Joe", Rel = "Father"}, new {Name="Ed", Rel="Brother"} };
//Get the names
var exceptedNames = ageItems.Select (a => a.Name).Except(relationItems.Select (r => r.Name));
//At this point, we have an `IEnumerable` containing 'Marry', we need to get the instances
var exceptedItems = ageItems.Where(a => exceptedNames.Contains(a.Name));
Of course, being LINQ, you can whack it all into one call:
var exceptedItems = ageItems.Where (a => ageItems.Select (b => b.Name).Except(relationItems.Select (r => r.Name)).Contains(a.Name));
You can't use the .Except overload that takes an IEqualityComparer instance as your classes differ, and IEqualityComparer can only compare two items of the same type, hence we have to generalise and pull out the same fields.

dynamic asc desc sort

I am trying to create table headers that sort during a back end call in nhibernate. When clicking the header it sends a string indicating what to sort by (ie "Name", "NameDesc") and sending it to the db call.
The db can get quite large so I also have back end filters and pagination built into reduce the size of the retrieved data and therefore the orderby needs to happen before or at the same time as the filters and skip and take to avoid ordering the smaller data. Here is an example of the QueryOver call:
IList<Event> s =
session.QueryOver<Event>(() => #eventAlias)
.Fetch(#event => #event.FiscalYear).Eager
.JoinQueryOver(() => #eventAlias.FiscalYear, () => fyAlias, JoinType.InnerJoin, Restrictions.On(() => fyAlias.Id).IsIn(_years))
.Where(() => !#eventAlias.IsDeleted);
.OrderBy(() => fyAlias.RefCode).Asc
.ThenBy(() => #eventAlias.Name).Asc
.Skip(numberOfRecordsToSkip)
.Take(numberOfRecordsInPage)
.List();
How can I accomplish this?
One way how to achieve this (one of many, because you can also use some fully-typed filter object etc or some query builder) could be like this draft:
Part one and two:
// I. a reference to our query
var query = session.QueryOver<Event>(() => #eventAlias);
// II. join, filter... whatever needed
query
.Fetch(#event => #event.FiscalYear).Eager
var joinQuery = query
.JoinQueryOver(...)
.Where(() => !#eventAlias.IsDeleted)
...
Part three:
// III. Order BY
// Assume we have a list of strings (passed from a UI client)
// here represented by these two values
var sortBy = new List<string> {"Name", "CodeDesc"};
// first, have a reference for the OrderBuilder
IQueryOverOrderBuilder<Event, Event> order = null;
// iterate the list
foreach (var sortProperty in sortBy)
{
// use Desc or Asc?
var useDesc = sortProperty.EndsWith("Desc");
// Clean the property name
var name = useDesc
? sortProperty.Remove(sortProperty.Length - 4, 4)
: sortProperty;
// Build the ORDER
order = order == null
? query.OrderBy(Projections.Property(name))
: query.ThenBy(Projections.Property(name))
;
// use DESC or ASC
query = useDesc ? order.Desc : order.Asc;
}
Finally the results:
// IV. back to query... call the DB and get the result
IList<Event> s = query
.List<Event>();
This draft is ready to do sorting on top of the root query. You can also extend that to be able to add some order statements to joinQuery (e.g. if the string is "FiscalYear.MonthDesc"). The logic would be similar, but built around the joinQuery (see at the part one)

Linq List contains specific values

I need to know if the List I am working with contains only some specific values.
var list = new List<string> { "First", "Second", "Third" };
If I want to know if the List contain at least one item with the value "First" I use the Any keyword:
var result = list.Any(l => l == "First");
But how I can write a Linq expression that will return true/false only if the List contains "First" and "Second" values?
I'm not entirely sure what you want, but if you want to ensure that "First" and "Second" are represented once, you can do:
var result = list.Where(l => l == "First" || l =="Second")
.Distinct()
.Count() == 2;
or:
var result = list.Contains("First") && list.Contains("Second");
If you've got a longer "whitelist", you could do:
var result = !whiteList.Except(list).Any();
On the other hand, if you want to ensure that all items in the list are from the white-list and that each item in the white-list is represented at least once, I would do:
var set = new HashSet(list);
set.SymmetricExceptWith(whiteList);
var result = !set.Any();
EDIT: Actually, Jon Skeet's SetEquals is a much better way of expressing the last bit.
Your question is unclear.
From the first sentence, I'd expect this to be what you're after:
var onlyValidValues = !list.Except(validValues).Any();
In other words: after you've stripped out the valid values, the list should be empty.
From the final sentence, I'd expect this:
var validSet = new HashSet<string>(requiredValues);
var allAndOnlyValidValues = validSet.SetEquals(candidateSequence);
Note that this will still be valid if your candidate sequence contains the same values multiple times.
If you could clarify exactly what your success criteria are, it would be easier to answer the question precisely.
You can use Intersect to find matches:
var list = new List<string> { "First", "Second", "Third" };
var comparelist = new List<string> { "First", "Second" };
var test = list.Intersect(comparelist).Distinct().Count() == comparelist.Count();

Filtering a List with another List Inclusive

i have a list of filter names: FILTERBYNAMES
my query result items each contain a name list: NAMES
I want to filter the result an take all items whose name list contains at least one name in the FILTERNAMELIST:
results= result.where(r=>r.NAMES.CONTAINS(...?)...?
I think you need something like:
var results = list.Where(i => i.Names
.Any(name => filterNameList.Contains(name)));
You can solve this by looking at the intersection of the two name sets.
var filteredResult = result.Where(i => i.Names.Intersect(filter).Any());
To limit the enumerations of the filter, you could use a hashset...
HashSet<string> hashedFilter = new HashSet<string>(filterByNames);
var results = result
.Where(x => x.Names
.Any(name => hashedFilter.Contains(name))
);

Resources