How to sort MutableLiveData<List<Book>> - sorting

I have MutableLiveData> in ViewModel. How can we sort it based on book name, id and so on.

You can use map function to transform your LiveData.
val unsortedBooks: LiveData<Book> = //...
val sortedBooks: LiveData<Book> = Transformations
.map(unsortedBooks, Function { books ->
//sort your `books` here and return the sorted list
})

Related

Kotlin - sort a map where value is a List

I have a MutableMap<String, List<CustomObject>> and I'm trying to sort the map by a date field in the CustomObject. I tried something like this
val unsortedMap: MutableMap<String, List<CustomObject>> // data already populated
val sortedMap: MutableMap<String, List<CustomObject>> = LinkedHashMap()
unsortedMap.entries.sortedBy { s -> s.value.sortedBy { t -> t.dateField } }.forEach { it2 -> sortedMap[it2.key] = it2.value }
but I get a Type mismatch. Required: Comparable<List<CustomObject>> Found: List<CustomObject> in the block that sorts by dateField. Is there a way to accomplish this?
Thanks.
The problem is here:
sortedBy { s -> s.value.sortedBy { t -> t.dateField } }
The outer sortedBy needs the lambda to define something to allow it to compare different List<CustomObject>. However, you are "returning" just s.value.sortedBy { ... }. That is, you're returning a List<CustomObject> here, not something that can compare lists of custom objects.
If you want to sort your map by the earliest of all dateFields in each list, then you will want something like this:
sortedBy { s -> s.value.sortedBy { t -> t.dateField }.first().dateField }
This will first sort your list of objects by their dateField, and then extract the dateField from the first item in the list, and use that for comparison.
It turns out that sorting and then taking the first item is common enough that there's a function to simplify it:
sortedBy { s -> s.value.minBy { t -> t.dateField }!!.dateField }

Use full group record within title in dc-js geoChoropleth chart

I have a group for which elements after reduction look like this pseudocode :
{
key:"somevalue",
value: {
sum: the_total,
names:{
a: a_number,
b: b_number,
c:c_number
}
}
}
In my dc-js geoChoropleth graph the valueAccessor is (d) => d.value.sum
In my title, I would like to use the names component of my reduction. But when I use .title((d) => {...}), I can onjly access the key and the value resulting from the valueAccessor function instead of the original record.
Is that meant to be ?
This is a peculiarity of the geoChoropleth chart.
Most charts bind the group data directly to chart elements, but since the geoChoropleth chart has two sources of data, the map and the group, it binds the map data and hides the group data.
Here is the direct culprit:
_renderTitles (regionG, layerIndex, data) {
if (this.renderTitle()) {
regionG.selectAll('title').text(d => {
const key = this._getKey(layerIndex, d);
const value = data[key];
return this.title()({key: key, value: value});
});
}
}
It is creating key/value objects itself, and the value, as you deduced, comes from the valueAccessor:
_generateLayeredData () {
const data = {};
const groupAll = this.data();
for (let i = 0; i < groupAll.length; ++i) {
data[this.keyAccessor()(groupAll[i])] = this.valueAccessor()(groupAll[i]);
}
return data;
}
Sorry this is not a complete answer, but I would suggest adding a pretransition handler that replaces the titles, or alternately, using the key passed to the title accessor to lookup the data you need.
As I noted in the issue linked above, I think this is a pretty serious design bug.

Sort ids by entity property in redux store

I have a problem sorting the data in my redux-store.
My store looks like this:
state = {
ids: [1,2,3,4, /*...*/],
entities: {
1: {
id: 1,
time: 50
}
//...
}
};
In my reducer function I want to sort the ids, in this way my data will always be sorted and ready to use, without needing to sort it every time:
case LOAD_LIST_SUCCESS:
return Object.assign({}, state,
{ids: [state.ids, ...action.payload.normalized.result].sort()}, //Here is my problem...
{entities: [...state.entities, ...action.payload.normalized.entities.items});
How can I sort the ids array by the entities time property?
To sort by the time property, you would need to do something more advanced with the sort function.
I've made a quick example:
[state.ids, ...action.payload.normalized.result].sort((id1, id2) => {
const entity1 = state.entities[id1]
const entity2 = state.entities[id2]
if (entity1.time < entity2.time) {
return -1
}
if (entity1.time > entity2.time) {
return 1
}
return 0
})
However, this approach will not take into account any normalized entities attached to the current action because the state's entities list will have not been updated yet, so you might need to assign the new state to a variable, then sort the ids based on the entities in the new state, and THEN return it as the result of the LOAD_LIST_SUCCESS case.

Distinct by Attribute inside the item on my collection

I have an IEnumerable<MyObject> collection, with N MyObject elements.
MyObject is a class with a Title, a Description and an ID (as string).
I'd like to have my collection with distinct list of MyObject, due to the ID field.
So if 2 MyObject have got the same ID, one should be deleted (don't care which, I need unique ID).
How can I do it with LINQ?
Tried :
myList = myList.GroupBy(o => o.ID);
but seems I need a cast?
You can implement a custom IEqualityComparer<MyObject>. Then you can use Enumerable.Distinct to filter out duplicates.
class DistinctIdComparer : IEqualityComparer<MyObject> {
public bool Equals(MyObject x, MyObject y) {
return x.Id == y.Id;
}
public int GetHashCode(MyObject obj) {
return obj.Id.GetHashCode();
}
}
Now it's simple:
IEnumerable<MyObject> distinct = myObjects.Distinct(new DistinctIdComparer());
Or you can use Enumerable.GroupBy what is even simpler:
distinct = myObjects.GroupBy(o => o.ID)
.Select(g => g.First());
If you wants only unique id then you can try.
var uniqueIds = myObjects.Select(x=>x.ID).Distinct();
Or for Unique ID Objects
List<MyObject> objs = new List<MyObject> ();
myObjects.ForEach(x=>{
if(objs.Find(y=>y.ID == x.ID)== null)
objs.Add(x);
});

How can I create an Expression within another Expression?

Forgive me if this has been asked already. I've only just started using LINQ. I have the following Expression:
public static Expression<Func<TblCustomer, CustomerSummary>> SelectToSummary()
{
return m => (new CustomerSummary()
{
ID = m.ID,
CustomerName = m.CustomerName,
LastSalesContact = // This is a Person entity, no idea how to create it
});
}
I want to be able to populate LastSalesContact, which is a Person entity.
The details that I wish to populate come from m.LatestPerson, so how can I map over the fields from m.LatestPerson to LastSalesContact. I want the mapping to be re-useable, i.e. I do not want to do this:
LastSalesContact = new Person()
{
// Etc
}
Can I use a static Expression, such as this:
public static Expression<Func<TblUser, User>> SelectToUser()
{
return x => (new User()
{
// Populate
});
}
UPDATE:
This is what I need to do:
return m => (new CustomerSummary()
{
ID = m.ID,
CustomerName = m.CustomerName,
LastSalesContact = new Person()
{
PersonId = m.LatestPerson.PersonId,
PersonName = m.LatestPerson.PersonName,
Company = new Company()
{
CompanyId = m.LatestPerson.Company.CompanyId,
etc
}
}
});
But I will be re-using the Person() creation in about 10-15 different classes, so I don't want exactly the same code duplicated X amount of times. I'd probably also want to do the same for Company.
Can't you just use automapper for that?
public static Expression<Func<TblCustomer, CustomerSummary>> SelectToSummary()
{
return m => Mapper.Map<TblCustomer, CustommerSummary>(m);
}
You'd have to do some bootstrapping, but then it's very reusable.
UPDATE:
I may not be getting something, but what it the purpose of this function? If you just want to map one or collection of Tbl object to other objects, why have the expression?
You could just have something like this:
var customers = _customerRepository.GetAll(); // returns IEnumerable<TblCustomer>
var summaries = Mapper.Map<IEnumerable<TblCustomer>, IEnumerable<CustomerSummary>>(customers);
Or is there something I missed?
I don't think you'll be able to use a lambda expression to do this... you'll need to build up the expression tree by hand using the factory methods in Expression. It's unlikely to be pleasant, to be honest.
My generally preferred way of working out how to build up expression trees is to start with a simple example of what you want to do written as a lambda expression, and then decompile it. That should show you how the expression tree is built - although the C# compiler gets to use the metadata associated with properties more easily than we can (we have to use Type.GetProperty).
This is always assuming I've understood you correctly... it's quite possible that I haven't.
How about this:
public static Person CreatePerson(TblPerson data)
{
// ...
}
public static Expression<Func<TblPerson, Person>> CreatePersonExpression()
{
return d => CreatePerson(d);
}
return m => (new CustomerSummary()
{
ID = m.ID,
CustomerName = m.CustomerName,
LastSalesContact = CreatePerson(m.LatestPerson)
});

Resources