java 8 streams copy specific objects from map to list - java-8

Looking for alternative code in Java8/streams.
I want to copy specific values from a Map into a List using a predefined array of Keys.
The code to accomplish this task in Java 7 is as follows:
public List<Fruit> getFruitList(Map<String, Fruit> fruitMap) {
final String[] fruitNames = { "apple", "banana", "mango" };
final ArrayList<Fruit> fruitList = new ArrayList<>(fruitNames.length);
for (int i = 0; i < fruitNames.length; i++) {
final String fruitName = fruitNames[i];
final Fruit fruit = fruitMap.get(fruitName);
if (fruit != null) {
fruitList.add(fruit);
}
}
fruitList.trimToSize();
return fruitList;
}

Figured out a possible solution myself:
return Stream.of(fruitNames)
.map(fruitMap::get)
.filter(Objects::nonNull)
.collect(Collectors.toList());

Related

Multiple sorting on single index of Algolia

Can we put multiple sorting/custom ranking on single index of Algolia without creating multiple replica indexes for each sorting.
Lets understand with example suppose my application is SalesManagement and I create 3 replicas MobileSale,LaptopSale and PhoneSale and then in each one I put custom sorting to type = 'mobile',type = 'laptop' and type = 'phone' respectively.
Instead of doing above I just want to create one index and put sorting on compile time by sending different settings by using IndexSetting in my code so I don't need to create multiple indexes
Using ranking property of IndexSetting it worked for me
private readonly SearchClient algoliaClient;
private readonly SearchIndex feedIndex;
public AlgoliaService( )
{
algoliaClient = new SearchClient("app-id", "api-key");
SearchIndex = algoliaClient.InitIndex(_defaultSettings.Algolia.FeedIndex);
algoliaClient.InitIndex("user-index-name");
}
public async Task SetCustomSortingAttributes(string sortBy)
{
if (sortBy != null)
{
List<string> sortingAttributesList = new List<string>();
StringBuilder sortAttribute = new StringBuilder();
if (sortBy == "most_viewed")
{
sortAttribute.Append("desc(most_viewed)");
}
else if (sortBy == "entityUniqueViews" )
{
sortAttribute.Append("desc(entityUniqueViews)");
}
else if (sortBy == "latest")
{
sortAttribute.Append("desc(latest)");
}
else if (sortBy == "price_asc")
{
sortAttribute.Append("asc(price)");
}
else
{
sortAttribute.Append("desc(price)");
}
sortingAttributesList.Add(sortAttribute.ToString());
IndexSettings settings = new IndexSettings
{
Ranking = sortingAttributesList
};
var setIndexSetting = await feedIndex.SetSettingsAsync(settings);
}
}

Dart - Best sort Algorithm for pushing a list of objects to a list of First Class Lists

I have a list of objects that are retrieved from a DB. The object looks like this:
class MonthlyFinancePlan {
final int id;
final DateTime date;
final double incomeAfterTax;
final double totalToPayOut;
final double totalRemainingForMonth;
final Map<String, dynamic> items;
MonthlyFinancePlan({ this.id, this.date, this.incomeAfterTax, this.totalToPayOut, this.totalRemainingForMonth, this.items });
MonthlyFinancePlan.fromEntity(MonthlyFinancePlanEntity monthlyFinancePlanEntity):
this.id = monthlyFinancePlanEntity.id,
this.date = DateTime.parse(monthlyFinancePlanEntity.date),
this.incomeAfterTax = monthlyFinancePlanEntity.incomeAfterTax.toDouble(),
this.totalToPayOut = monthlyFinancePlanEntity.totalToPayOut.toDouble(),
this.totalRemainingForMonth = monthlyFinancePlanEntity.moneyRemainingForMonth.toDouble(),
this.items = monthlyFinancePlanEntity.items != null ? json.decode(monthlyFinancePlanEntity.items) : Map();
}
I need to sort these by date.year and then pass them into a first class List, I'd like to create a List of these First class lists so that all the MonthlyFinancePlan objects that are from the year 2020 are sorted and contained within the first class list, same for 2021, etc.
The first class list looks like this:
class YearlyFinancePlan {
List<MonthlyFinancePlan> _monthlyFinancePlanList;
int _year;
double _totalIncomeForYear;
double _totalOutGoingsForYear;
List<MonthlyFinancePlan> get items {
return this._monthlyFinancePlanList;
}
int get year {
return this._year;
}
double get totalIncomeForYear {
return this._totalIncomeForYear;
}
double get totalOutgoingsForYear {
return this._totalOutGoingsForYear;
}
YearlyFinancePlan(this._monthlyFinancePlanList) {
this._year = this._monthlyFinancePlanList.first.date.year;
this._totalIncomeForYear = this._setTotalIncomeFromList(this._monthlyFinancePlanList);
this._totalOutGoingsForYear = this._setTotalOutGoingsForYear(this._monthlyFinancePlanList);
}
double _setTotalIncomeFromList(List<MonthlyFinancePlan> monthlyFinancePlanList) {
double totalIncome;
monthlyFinancePlanList.forEach((plan) => totalIncome += plan.incomeAfterTax);
return totalIncome;
}
double _setTotalOutGoingsForYear(List<MonthlyFinancePlan> monthlyFinancePlanList) {
double totalOutgoings;
monthlyFinancePlanList.forEach((plan) => totalOutgoings += plan.totalToPayOut);
return totalOutgoings;
}
}
My question is, what sort algorithm would be best suited for what I need? I don't have any code to show as I don't know what sort algorithm to use. I'm not looking for anyone to write my code, but more to guide me through it.
Any help would be greatly appreciated
I've created a Mapper that checks if the MonthlyPlanner.date.year exists as a key in a standard Dart Map and adds it if it doesn't exist. Once the check is complete, it also calls the addMonthlyPlan method to add the entry to the MonthlyPlan to the correct YearlyPlan like so:
class FinancePlanMapper {
static Map<int, YearlyFinancePlan> toMap(List<MonthlyFinancePlan> planList) {
Map<int, YearlyFinancePlan> planMap = Map();
planList.forEach((monthlyPlan) {
planMap.putIfAbsent(monthlyPlan.date.year, () => YearlyFinancePlan(List()));
planMap[monthlyPlan.date.year].addMonthlyPlan(monthlyPlan);
});
return planMap;
}
}
I'm not too sure whether it's the most efficient way of sorting but I plan to refactor it as much as possible. I've also updated the YearlyFinancePlan object so that it doesn't initialise any fields on construction, which would cause the object to throw an error when being initialised with an empty list:
class YearlyFinancePlan {
List<MonthlyFinancePlan> _monthlyFinancePlanList;
List<MonthlyFinancePlan> get items {
return this._monthlyFinancePlanList;
}
int get year {
return this.items.first.date.year;
}
double get totalIncomeForYear {
return this._setTotalIncomeFromList(this._monthlyFinancePlanList);
}
double get totalOutgoingsForYear {
return this._setTotalOutGoingsForYear(this._monthlyFinancePlanList);
}
YearlyFinancePlan(this._monthlyFinancePlanList);
void addMonthlyPlan(MonthlyFinancePlan plan) {
this._monthlyFinancePlanList.add(plan);
}
double _setTotalIncomeFromList(List<MonthlyFinancePlan> monthlyFinancePlanList) {
double totalIncome = 0;
monthlyFinancePlanList.forEach((plan) => totalIncome += plan.incomeAfterTax);
return totalIncome;
}
double _setTotalOutGoingsForYear(List<MonthlyFinancePlan> monthlyFinancePlanList) {
double totalOutgoings = 0;
monthlyFinancePlanList.forEach((plan) => totalOutgoings += plan.totalToPayOut);
return totalOutgoings;
}
}

C# Sort array of Objects by object type (Icomparable?)

I want to sort anarray by the object type. So all songs are together, all book are together, and all movies are together.
I am reading a file and determine what each object should be. then creating the object and adding it to the array.
EDIT: Here is the actual code.
static Media[] ReadData()
{
List<Media> things = new List<Media>();
try
{
String filePath = "resources/Data.txt";
string Line;
int counter = 0; // used to check if you have reached the max
number of allowed objects (100)
using (StreamReader File = new System.IO.StreamReader(filePath))
{
while ((Line = File.ReadLine()) != null)
{
This is where each object is created. The file
search for a key word in the beginning of the line, then
creates the corresponding object. It will split the
information on the first line of the object and will
read each line until a "-" character is found and
pass each line into the summary. The summary is then
decrypted and the created object is passed into an
array List. Finally if the array list reaches 100, it
will print "You have reach max number of objects" and
stop reading the file.
if (Line.StartsWith("BOOK"))
{
String[] tempArray = Line.Split('|');
//foreach (string x in tempArray){Console.WriteLine(x);} //This is used
for testing
Book tempBook = new Book(tempArray[1],
int.Parse(tempArray[2]), tempArray[3]);
while ((Line = File.ReadLine()) != null)
{
if (Line.StartsWith("-")){break;}
tempBook.Summary = tempBook.Summary + Line;
}
tempBook.Summary = tempBook.Decrypt();
things.Add(tempBook);
counter++;
}
else if (Line.StartsWith("SONG"))
{
String[] tempArray = Line.Split('|');
//foreach (string x in tempArray)
{Console.WriteLine(x);} //This is used for testing
Song tempSong = new Song(tempArray[1],
int.Parse(tempArray[2]), tempArray[3], tempArray[4]);
things.Add(tempSong);
counter++;
}
else if (Line.StartsWith("MOVIE"))
{
String[] tempArray = Line.Split('|');
//foreach (string x in tempArray)
{Console.WriteLine(x);} //This is used for testing
Movie tempMovie = new Movie(tempArray[1],
int.Parse(tempArray[2]), tempArray[3]);
while ((Line = File.ReadLine()) != null)
{
if (Line.StartsWith("-")) { break; }
tempMovie.Summary = tempMovie.Summary + Line;
}
tempMovie.Summary = tempMovie.Decrypt();
things.Add(tempMovie);
counter++;
}
if (counter == 100)
{
Console.WriteLine("You have reached the maximum number of media
objects.");
break;
}
}
File.Close();
}
}
return things.ToArray(); // Convert array list to an Array and return the
array.
}
In the main code, I have this:
Media[] mediaObjects = new Media[100];
Media[] temp = ReadData();
int input; // holds the input from a user to determin which action to take
for (int i = 0; i<temp.Length;i++){ mediaObjects[i] = temp[i]; }
I want the array of mediaObjects to be sorted by the what type of objects.
I have also used Icomparable to do an arrayList.sort() but still no luck.
public int CompareTo(object obj)
{
if (obj == null)
{
return 1;
}
Song temp = obj as Song;
if (temp != null)
{
//Type is a string
return this.Type.CompareTo(temp.Type);
}
else
{
return 1;
}
}
So I see you have BOOK, SONG and MOVIE types.
This is a classic case of implementing the IComparable interface - although you are correct with the interface name to implement, you are not using this correctly.
Create a base class by the name MediaObject - this will be the main one for your other types of objects you create.
Add the correct properties you need. In this case, the media type is the one in need.
Let this class implement IComparable to help you with the comparison.
override the CompareTo() method in the PROPER way
public class MediaObject : IComparable
{
private string mediaType;
public string MediaType
{
get {return mediaType;}
set {mediaType=value;}
}
public MediaObject(string mType)
{
MediaType = mType;
}
int IComparable.CompareTo(object obj)
{
MediaObject mo = (MediaObject)obj;
return String.Compare(this.MediaType,mo.MediaType); //implement a case insensitive comparison if needed (for your research)
}
}
You can now compare the MediaObject objects In your main method directly.
Thank for the advice. I ended up just reformating how I was creating the list while reading it. I made multiple lists for each object then just happened each one on to the master list so It showed up sorted. I wish I figured that out before I made this long post.
As far as I could find, you can't sort by the type of object in a generic array. If anyone has a better solution feel free to post it.

Java 8 is not maintaining the order while grouping

I m using Java 8 for grouping by data. But results obtained are not in order formed.
Map<GroupingKey, List<Object>> groupedResult = null;
if (!CollectionUtils.isEmpty(groupByColumns)) {
Map<String, Object> mapArr[] = new LinkedHashMap[mapList.size()];
if (!CollectionUtils.isEmpty(mapList)) {
int count = 0;
for (LinkedHashMap<String, Object> map : mapList) {
mapArr[count++] = map;
}
}
Stream<Map<String, Object>> people = Stream.of(mapArr);
groupedResult = people
.collect(Collectors.groupingBy(p -> new GroupingKey(p, groupByColumns), Collectors.mapping((Map<String, Object> p) -> p, toList())));
public static class GroupingKey
public GroupingKey(Map<String, Object> map, List<String> cols) {
keys = new ArrayList<>();
for (String col : cols) {
keys.add(map.get(col));
}
}
// Add appropriate isEqual() ... you IDE should generate this
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final GroupingKey other = (GroupingKey) obj;
if (!Objects.equals(this.keys, other.keys)) {
return false;
}
return true;
}
#Override
public int hashCode() {
int hash = 7;
hash = 37 * hash + Objects.hashCode(this.keys);
return hash;
}
#Override
public String toString() {
return keys + "";
}
public ArrayList<Object> getKeys() {
return keys;
}
public void setKeys(ArrayList<Object> keys) {
this.keys = keys;
}
}
Here i am using my class groupingKey by which i m dynamically passing from ux. How can get this groupByColumns in sorted form?
Not maintaining the order is a property of the Map that stores the result. If you need a specific Map behavior, you need to request a particular Map implementation. E.g. LinkedHashMap maintains the insertion order:
groupedResult = people.collect(Collectors.groupingBy(
p -> new GroupingKey(p, groupByColumns),
LinkedHashMap::new,
Collectors.mapping((Map<String, Object> p) -> p, toList())));
By the way, there is no reason to copy the contents of mapList into an array before creating the Stream. You may simply call mapList.stream() to get an appropriate Stream.
Further, Collectors.mapping((Map<String, Object> p) -> p, toList()) is obsolete. p->p is an identity mapping, so there’s no reason to request mapping at all:
groupedResult = mapList.stream().collect(Collectors.groupingBy(
p -> new GroupingKey(p, groupByColumns), LinkedHashMap::new, toList()));
But even the GroupingKey is obsolete. It basically wraps a List of values, so you could just use a List as key in the first place. Lists implement hashCode and equals appropriately (but you must not modify these key Lists afterwards).
Map<List<Object>, List<Object>> groupedResult=
mapList.stream().collect(Collectors.groupingBy(
p -> groupByColumns.stream().map(p::get).collect(toList()),
LinkedHashMap::new, toList()));
Based on #Holger's great answer. I post this to help those who want to keep the order after grouping as well as changing the mapping.
Let's simplify and suppose we have a list of persons (int age, String name, String adresss...etc) and we want the names grouped by age while keeping ages in order:
final LinkedHashMap<Integer, List<String> map = myList
.stream()
.sorted(Comparator.comparing(p -> p.getAge())) //sort list by ages
.collect(Collectors.groupingBy(p -> p.getAge()),
LinkedHashMap::new, //keeps the order
Collectors.mapping(p -> p.getName(), //map name
Collectors.toList())));

C# List with Unique Entries

I have a list like this,
List A
ItemNum FileName
001 A.txt,B.txt,A.txt,B.txt
002 A.txt,C.txt,A.txt,C.txt
I need to make a list like this.
ItemNum FileName
001 A.txt,B.txt
002 A.txt,C.txt
Is there any way to do it?
Case sensitive, in a method format:
public List<string> ToDistinct(IEnumerable<string> input)
{
List<string> unique = new List<string>();
foreach (string s in input)
{
List<string> files = s.Split(',').ToList();
unique.Add(String.Join(",", files.Distinct()));
}
return unique;
}
Here's a console method that displays the output like you have above and you can tweak it if you like:
public static void Main(string[] args)
{
List<string> input = new List<string>{"A.txt,B.txt,A.txt,B.txt", "A.txt,C.txt,A.txt,C.txt"};
//Display Input
Console.WriteLine("Input");
Console.WriteLine("ItemNum FileNames");
for(int i = 0; i < input.Count(); i++)
{
Console.WriteLine(String.Format(" {0,-23:000}{1}", i + 1, input[i]));
}
//Build the Unique List
List<string> unique = new List<string>();
foreach (string s in input)
{
List<string> files = s.Split(',').ToList();
unique.Add(String.Join(",", files.Distinct()));
}
//Display Output
Console.WriteLine();
Console.WriteLine("Output");
Console.WriteLine("ItemNum FileNames");
for(int i = 0; i < unique.Count(); i++)
{
Console.WriteLine(String.Format(" {0,-23:000}{1}", i + 1, unique[i]));
}
Console.ReadKey();
}
I'm going to suggest that you convert the FileName's to a List<string>, then all you need is this:
listA.ForEach(x => x.FileNames = x.FileNames.Distinct().ToList());
If there is no specific reason why you're storing what is - for all intents - a list in a string.. why not store it as one? List<string> will allow you to add and remove as you see fit.
List<Item> list = new List<Item>();
list.Add(new Item("001", "A.txt,B.txt,A.txt,B.txt"));
list.Add(new Item("002", "A.txt,C.txt,A.txt,C.txt"));
var newList = from l in list
select new Item() { ItemNum = l.ItemNum,
FileName = string.Join(",", l.FileName.Split(',').Distinct()) };

Resources