Group the list of Objects and convert to a map using java8 - collections

`Hi,
I have a list of Employees employeeList (assume this list has some values present)
List<Employee> employeeList ;
Say, My Employee DTO is something like below :
Employee {
List<Book> bookList;
}
Book DTO:
Book {
private String bookId;
private String bookName;
}
I have to stream through the employeeList and group the employees with same book Id and convert to a map having key as the BookId and value as list of Employees.
I want to achieve this using java8 concepts. Please help!
I tried to use Collectors.groupingBy but I have to traverse through another List of Books inside list of Employees.
Could not figure out how?`

You can flatten the Employee list to pairs of Employee, Book ID and then collect to the Map you want.
Something like this (not tested):
Map<String,List<Employee>> map =
employeeList.stream()
.flatMap(e -> e.getBookList()
.stream()
.map(book -> new SimpleEntry<String,Employee>(book.getID (), e)))
.collect (Collectors.groupingBy (Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue,
Collectors.toList())));

You can achieve it with flatmapping, capturing a "bookId to employee" pair (you can use a temporary record as of newer Java or SimpleEntry with Java 8), grouping by the bookId and mapping to the final structure (List<Employee> to Employee).
record BookEmployee(String bookId, Employee employee) {}
Map<String, List<Employee>> map = employeeList.stream()
.collect(Collectors.flatMapping(
e -> e.getBookList()
.stream()
.map(b -> new BookEmployee(b.getBookId(), e)),
Collectors.groupingBy(
BookEmployee::bookId,
Collectors.mapping(
BookEmployee::employee,
Collectors.toList()))));

Related

Selecting only one column linq lambda query asp.net

I am quite new to entity framework and linq but basically I am using data first and my database has a table called tblNumbers and it has 2 columns, an id column and a numbers column which is populated with int values, I want to populate only the number values into my list but when I try do this I get an error saying that I cannot implicitly convert system.collections.generic.list< int> to system.collections.generic.list<projectname.Models.tblNumber>. I am not sure where to go from this, any help would be much appreciated.
Here is my code:
private DatabaseEntities db = new DatabaseEntities();
public ActionResult MyAction()
{
db.Configuration.ProxyCreationEnabled = false;
List<tblNumber> numbers = db.tblNumbers.Select(column => column.numbers).ToList();
return View();
}
Your List<tblNumber> numbers is expecting a list of tblNumber type and you are selecting column.numbers only
var numbers = db.tblNumbers.Select(column => column.numbers).ToList();

How to retrieve a property of collection as a collection of string using Java Stream api

I have a list of class Category which contains many attributes like code, name, description, supercategory, productlist, etc. Now I want to iterate over it and retrieve each category's code and store add it in list of string. This is how I am doing it with old school way. I want to know if this can be done in better, cleaner and efficient way with Java 8 Streams.
List<Category> categories = categoryService.getCategoriesForProductCode(productCode);
List<String> categoryCodes = new ArrayList<>();
if(CollectionUtils.isNotEmpty(categories)){
for(Category cat : categories){
categoryCodes.add(cat.getCode);
}
}
You can do like this
categoryCodes = categories.stream()
.map(category->catgory.getCode()) // .map(Category::getCode)
.collect(Collectors.toList());

java8 how to collection data and add as the properties of object then to a List

Before java8 we write code like this:
List<ResultDTO> resources = Lists.newArrayList();
List<Product> productList = details.getProducts();
for (Product product : productList) {
ResultDTO result = new ResultDTO();
result.setName(product.getName);
result.setNumber(product.getNumber);
resources.add(resourceDetail);
}
And Java8 I write like this:
List<ResultDTO> resources = Lists.newArrayList();
details.getProducts.stream().forEach( product -> {
ResultDTO result = new ResultDTO();
result.setName(product.getName);
result.setNumber(product.getNumber);
resources.add(resourceDetail);
} );
I wonder if there are some tips when we traversing stream create ResultDTO objects set its properties and then to a list ?
Thanks in advance.
Creating a list and modifying it inside the stream operations is an anti-pattern. You should let the stream create the list for you:
List<ResultDTO> resources =
details.getProducts()
.stream()
.map(this::createResultDTO)
.collect(Collectors.toList());
Where the createResultDTO method would create a ResultDTO from a Product (you can of course inline its code inside map, but it's much less readable).
As JB mentioned, you would want to create list from the stream.
List<ResultDTO> resources = details.getProducts()
.stream()
.map(this::createResultDTO)
.collect(Collectors.toList());
And here would be the createResultDTO method.
public ResultDTO createResultDTO(Product p){
ResultDTO result = new ResultDTO();
result.setName(p.getName);
result.setNumber(p.getNumber);
return result;
}
You can put this method in the same class and use
.map(this::createResultDTO)
or in a different class called ProductResultDTO and use the following:
.map(ProductResultDTO::createResultDTO)

What should be the type parameter for List<T> and .Query<T> for joined table?

I am very new to Xamarin Forms and SQLite. I have the following method that returns a list from two joined tables. My problem is I don't know what is the right type parameter the List<T> and .Query<> should have to be able to get the values of both Category and Phrase table. Can anyone enlighten me on this one?
public List<?> GetWordsByCategory(int category)
{
lock (locker)
{
var words = databaseConnection
.Query<?>("Select Category.*, Phrase.*
From Category
Join Phrase on Category.Id = Phrase.CategoryId
Where Category.Id = 1")
.ToList();
return words;
}
}
I have tried List<Category> but would only return the properties of the Category table likewise List<Phrase>
You can return a dynamic or create a new class.
But I would suggest you to use the SQLite.Net PCL which is a wrapper around SQL and which enables you to query database like EF using linq and lamda than string queries.
You can look into this similar question which should help you.

LINQ to SQL - How to select specific columns and return strongly typed list

I'm trying to use LINQ to SQL to select a few specific columns from a table and return the result as a strongly typed list of objects.
For Example:
var result = (from a in DataContext.Persons
where a.Age > 18
select new Person
{
Name = a.Name,
Age = a.Age
}
).ToList();
Any help would be greatly appreciated.
It builds fine, but when I run it, I get the error. Explicit construction of entity type MyEntity in query is not allowed.
Basically you are doing it the right way. However, you should use an instance of the DataContext for querying (it's not obvious that DataContext is an instance or the type name from your query):
var result = (from a in new DataContext().Persons
where a.Age > 18
select new Person { Name = a.Name, Age = a.Age }).ToList();
Apparently, the Person class is your LINQ to SQL generated entity class. You should create your own class if you only want some of the columns:
class PersonInformation {
public string Name {get;set;}
public int Age {get;set;}
}
var result = (from a in new DataContext().Persons
where a.Age > 18
select new PersonInformation { Name = a.Name, Age = a.Age }).ToList();
You can freely swap var with List<PersonInformation> here without affecting anything (as this is what the compiler does).
Otherwise, if you are working locally with the query, I suggest considering an anonymous type:
var result = (from a in new DataContext().Persons
where a.Age > 18
select new { a.Name, a.Age }).ToList();
Note that in all of these cases, the result is statically typed (it's type is known at compile time). The latter type is a List of a compiler generated anonymous class similar to the PersonInformation class I wrote above. As of C# 3.0, there's no dynamic typing in the language.
UPDATE:
If you really want to return a List<Person> (which might or might not be the best thing to do), you can do this:
var result = from a in new DataContext().Persons
where a.Age > 18
select new { a.Name, a.Age };
List<Person> list = result.AsEnumerable()
.Select(o => new Person {
Name = o.Name,
Age = o.Age
}).ToList();
You can merge the above statements too, but I separated them for clarity.
The issue was in fact that one of the properties was a relation to another table. I changed my LINQ query so that it could get the same data from a different method without needing to load the entire table.
Thank you all for your help!
Make a call to the DB searching with myid (Id of the row) and get back specific columns:
var columns = db.Notifications
.Where(x => x.Id == myid)
.Select(n => new { n.NotificationTitle,
n.NotificationDescription,
n.NotificationOrder });

Resources