I have two hashmaps one is containing keys and other is containing key with object value.
Here are my two maps and its value
1st one is:
newProdList = [18=, 2=, 21=1099887, 5=, 22=1099888, 7=, 14=]
and 2nd one is:
oldList = [2=Stock [location=AAQ-08-2, stockQty=150,
productCode=null, productName=Emergence Men's Running Shoes,
division=Shoes, category=Running], 3=Stock [location=AAR-01-1,
stockQty=192, productCode=19234402, productName=Men's Running Shoes
19234402, division=Shoes, category=Running], 4=Stock
[location=BAN-08-1, stockQty=190, productCode=19108206,
productName=Carson 2 New Core Men?s Running Shoes, division=Shoes,
category=Running] , 21 =Stock [location=BAN-08-1, stockQty=190,
productCode=19108206, productName=Carson 2 New Core Men?s Running
Shoes, division=Shoes, category=Running]]
I want to iterate newProductList and use there keys in oldList that generate List of objects.
It is simply done by this:
List<Stock> stocks = new ArrayList<>();
for(Entry<?, ?> e: newProductList.entrySet()){
Stock s = (Stock) oldProdList.get(e.getKey());
stocks.add(s);
}
System.out.println(stocks);
But I want to use Stream api.
Since you're only using the keys of newProductList I'd suggest iterating over keySet() instead.
You then could do something like this:
List<Stock> stocks = newProductList.keySet().stream() //stream over the keys
.map(oldProdList::get) //map by calling get() on the old list
.filter(Objects::nonNull) //remove nulls
.collect(Collectors.toList()); //build the result list
Here we iterate over the keys, map them by doing a lookup, filter on non-null results (in case the lookup fails) and collect the result.
Iterate over the entrySet to get the corresponding key from newProdList in oldList and set the value from this entry from oldList in newProdList.
More reading here about Map Entry
Map<String,String> newProdList = new HashMap<>();
newProdList.put("18", null);
newProdList.put("2", null);
newProdList.put("21", "1099887");
newProdList.put("5", null);
newProdList.put("22", "1099888");
newProdList.put("7", null);
newProdList.put("14", null);
Map<String,String> oldList = new HashMap<>();
oldList.put("2", "Stock [location=AAQ-08-2, stockQty=150, productCode=null, productName=Emergence Men's Running Shoes, division=Shoes, category=Running]");
oldList.put("3", "Stock [location=AAR-01-1, stockQty=192, productCode=19234402, productName=Men's Running Shoes 19234402, division=Shoes, category=Running]");
oldList.put("4", "Stock [location=BAN-08-1, stockQty=190, productCode=19108206, productName=Carson 2 New Core Men?s Running Shoes, division=Shoes, category=Running]");
oldList.put("21", "Stock [location=BAN-08-1, stockQty=190, productCode=19108206, productName=Carson 2 New Core Men?s Running Shoes, division=Shoes, category=Running]");
newProdList.entrySet().stream().forEach(e -> e.setValue(oldList.get(e.getKey())));
More explanation with this nice schema, as requested.
Related
I have the following problem:
I want to remove duplicate data from a list of a Vo depending if the registered field is the same, I show you the solution that I am trying. Then this is the data from the list that I am making
List<MyVo> dataList = new ArrayList<MyVo>();
MyVo data1 = new MyVo();
data1.setValidated(1);
data1.setName("Fernando");
data1.setRegistered("008982");
MyVo data2 = new MyVo();
data2.setValidated(0);
data2.setName("Orlando");
data2.setRegistered("008986");
MyVo data3 = new MyVo();
data3.setValidated(1);
data3.setName("Magda");
data3.setRegistered("008982");
MyVo data4 = new MyVo();
data4.setValidated(1);
data4.setName("Jess");
data4.setRegistered("006782");
dataList.add(data1);
dataList.add(data2);
dataList.add(data3);
dataList.add(data4);
The first thing I have to do and separate it into two different lists depending on whether the data is validated or not, for that the value of the registered validated.
List<MyVo> registeredBusinesses = new ArrayList<MyVo>();
List<MyVo> unregisteredBusinesses = new ArrayList<MyVo>();
for (MyVo map : dataList) {
if (map.getValidated == 0) {
unregisteredBusinesses.add(map);
}else {
registeredBusinesses.add(map);
}
}
now the list of registered businesses I want to remove the data that is repeated with the same value from its registered field and make a new list. this is what it took but it doesn't work right
List<MyVo> duplicateList = registeredBusinesses.stream().filter(distictByRegistered(MyVo::getRegistered)).collect(Collectors.toList());
public static <T> Predicate<T> distictByRegistered(Function<? super T, ?> keyExtractor) {
Set<Object> seen = ConcurrentHashMap.newKeySet();
return t -> seen.add(keyExtractor.apply(t));
}
however using this method I get the following output:
{["validated":1,"name":"Fernando","registered":"008982"],
["validated":1,"name":"Jess","registered":"006782"]}
the output I want to obtain is the following:
the unregisteredBusinesses list:
{["validated":0,"name":"Orlando","registered":"008986"]}
the registeredBusinesses list:
{["validated":1,"name":"Jess","registered":"006782"]}
the registeredDuplicateBusinesses list:
{["validated":1,"name":"Fernando","registered":"008982"],
["validated":1,"name":"Magda","registered":"008982"]}
I don't know how to do it, could you help me? I would like to use lambdas to reduce the code, for example of the first for when I separate into two lists
You are looking for both registered and unregistered businesses. This is where instead of making use of 0 and 1, you could choose to implement the attribute as a boolean isRegistered such as 0 is false and 1 is true going forward. Your existing code with if-else could be re-written as :
Map<Boolean, List<MyVo>> partitionBasedOnRegistered = dataList.stream()
.collect(Collectors.partitioningBy(MyVo::isRegistered));
List<MyVo> unregisteredBusinesses = partitionBasedOnRegistered.get(Boolean.FALSE); // here
List<MyVo> registeredBusinesses = partitionBasedOnRegistered.get(Boolean.TRUE);
Your approach looks almost correct, grouping by Function.identity() will properly flag duplicates (based on equals() implementation!), you could also group by an unique property/id in your object if you have one, what you're missing is to manipulate the resulting map to get a list with all duplicates. I've added comments describing what's happening here.
List<MyVo> duplicateList = registeredBusinesses.stream()
.collect(Collectors.groupingBy(Function.identity()))
.entrySet()
.stream()
.filter(e -> e.getValue().size() > 1) //this is a stream of Map.Entry<MyVo, List<MyVo>>, then we want to check value.size() > 1
.map(Map.Entry::getValue) //We convert this into a Stream<List<MyVo>>
.flatMap(Collection::stream) //Now we want to have all duplicates in the same stream, so we flatMap it using Collections::stream
.collect(Collectors.toList()); //On this stage we have a Stream<MyVo> with all duplicates, so we can collect it to a list.
Additionally, you could also use stream API to split dataList into registered and unRegistered.
First we create a method isUnregistered in MyVo
public boolean isUnregistered() {
return getrRegistered() == 0;
}
Then
Map<Boolean, List<MyVo>> registeredMap = dataList.stream().collect(Collectors.groupingBy(MyVo::isUnregistered));
Where map.get(true) will be unregisteredBusinesses and map.get(false) registeredBusinesses
Familiarizing yourself with the concept of the Collectors.partitioningBy shall help you problem-solve this further. There are two places amongst your current requirement where it could be implied.
You are looking for both registered and unregistered businesses. This is where instead of making use of 0 and 1, you could choose to implement the attribute as a boolean isRegistered such as 0 is false and 1 is true going forward. Your existing code with if-else could be re-written as :
Map<Boolean, List<MyVo>> partitionBasedOnRegistered = dataList.stream()
.collect(Collectors.partitioningBy(MyVo::isRegistered));
List<MyVo> unregisteredBusinesses = partitionBasedOnRegistered.get(Boolean.FALSE); // here
List<MyVo> registeredBusinesses = partitionBasedOnRegistered.get(Boolean.TRUE);
After you try to groupBy the registered businesses based on the registration number(despite of identity), you require both the duplicate elements and the ones which are unique as well. Effectively all entries, but again partitioned into two buckets, i.e. one with value size == 1 and others with size > 1. Since grouping would ensure, minimum one element corresponding to each key, you can collect the required output with an additional mapping.
Map<String, List<MyVo>> groupByRegistrationNumber = // group registered businesses by number
Map<Boolean, List<List<MyVo>>> partitionBasedOnDuplicates = groupByRegistrationNumber
.entrySet().stream()
.collect(Collectors.partitioningBy(e -> e.getValue().size() > 1,
Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
If you access the FALSE values of the above map, that would provide you the groupedRegisteredUniqueBusiness and on the other hand values against TRUE key would provide you groupedRegisteredDuplicateBusiness.
Do take a note, that if you were to flatten this List<List<MyVo> in order to get List<MyVo> as output, you could also make use of the flatMapping collector which has a JDK inbuilt implementation with Java-9 and above.
I have a table in sql of doctor names and their clients
Each doctor has multiple clients
And one client can visit multiple do doctors
array and a simple table
[
{doctor="illies",client=4},
{doctor="illies",client=7},
{doctor="illies",client=1},
{doctor="houari",client=5},
{doctor="abdou",client=1},
{doctor="illies",client=2},
{doctor="abdou",client=1},
]
These data are already ordered So the task is To teach client know it's place in the queue
For example
The client with ID 1 Is in the third place in the doctor "illies"
And he's in the first place in the doctor "abdou"
I don't know if I explain it to you well A friend of mine suggest me to
Rearrange the array to a nested array like this (well this array is not totally correct but i has the idea)
[doctor="abdou" => clients=[cleint1="1",client2="2" ], doctor="illies"=>clients=[...] ]
now i just need an idea that could help me with my projet , all this work it to display the queue of the client (the position of the client in the doctor's queue), and thank you so much.
It seems that each row in the input array can be presented as a class like this:
class DocClient {
private String doctor;
private int client;
public String getDoctor() { return this.doctor; }
public int getClient() { return this.client; }
}
Then array or list of <DocClient> needs to be converted not into the "nested array" but into the map where doctor is used as a key, and the value is list of clients: Map<String, Integer> docClients.
This map can be conveniently built using Java Stream API using collectors Collectors.groupingBy and Collector.mapping:
List<DocClient> list = Arrays.asList(
new DocClient("illies", 4), new DocClient("illies", 4), new DocClient("illies", 1),
new DocClient("houari", 5), new DocClient("abdou", 1), new DocClient("illies", 2),
new DocClient("abdou", 2)
);
Map<String, List<Integer>> map = list
.stream()
.collect(Collectors.groupingBy(
DocClient::getDoctor, // use doctor as key via reference to getter
Collectors.mapping(
DocClient::getClient, // use `client` field
Collectors.toList() // convert to list
) // List<Integer> is value in map entry
));
// print the map
// map.forEach((doc, clients) -> System.out.printf("%s -> %s%n", doc. clients));
I am trying to load use this query and the values into a map
LinkedHashMap<SCRegionPriority, String> hash = new LinkedHashMap<>();
pstmt=("SELECT a.Id,a.RegionName,ISNULL(b.Priority,0) as priority
FROM dbo.region a left join dbo.SCMap b on a.Id = b.RegionId
and a.CountryId = b.CountryId and b.SCId=1 where a.CountryId ='1'")
ResultSet rs = pstmt.executeQuery();
con.commit();
while (rs.next()) {
SCPri c = new SCPri();
c.setRegionid(rs.getInt(1));
c.setRegionname(rs.getString(2));
c.setPriority(rs.getInt(3));
hash.put(c, String.valueOf(rs.getInt(3)));
}
the query gives me the following values:
1,0|2,1|3,1|4,2|...
And then I am trying to load this into the vaadin grid like the following:
List<HashMap<SCPri, String>> rows = new ArrayList<>();
LinkedHashMap<SCPri, String> fakeBean1 = subdao1.getSCMap(subcontractor.getId(),subcontractor.getCountryId());
rows.add(fakeBean1);
Grid<HashMap<SCPri, String>> grid2 = new Grid<>();
grid2.setItems(rows);
for (Map.Entry<SCPri, String> entry : s.entrySet()) {
grid2.addColumn(h -> h.get(entry.getKey().getRegionname())).setCaption(entry.getKey().getRegionname());
}
addComponents(grid2);
I am not able to load the grid with the columns dynamically generated and one editable row of with values underneath those columns.
I am trying to make the grid look like the following:
r1|r2|r3|r4
0 |1 |1 |2
I tried to follow the following two links but failed to get it working:
How to fill Vaadin Grid with Map items type
https://vaadin.com/forum/thread/16038356/grid-8-without-bean-class
How can I achieve this?
A single row with empty cells implies that the value provider callback for each cell returns null (or "").
In your case, the value provider callback is h -> h.get(entry.getKey().getRegionname()). Here, h represents the row object, i.e. your single HashMap<SCPri, String> instance. I'm assuming getRegionname() returns something like a String, which would surely cause null results from h.get() since h uses SCPri instances as they key. Changing the callback to h -> h.get(entry.getKey()) instead might do the trick.
It is an unfortunate leftover from the pre-generics times that Map::get accepts any Object without compilation errors instead of requiring you to pass an instance of the actual key type of the map.
Title says it all but for the sake of example.. I'm currently learning Java now and as a personal experiment I'm writing a soft representation of an ATM screen.
I'm attempting to store three hash maps inside of one value within a list of arrays. Thus, giving me the ability to add multiple strings, all containing their own set of three maps.
So - I want an Array List for "User" and within this list, will be three maps for "Checking" "Saving" and "CDs".
When adding a new User, this user is also given the ability to add/modify/remove three different "accounts."
Thoughts?
See if it could help you solve the problem
HashMap <String,HashMap> holder = new HashMap<>();
HashMap <Integer,Integer> hm1 = new HashMap<>();
HashMap <Integer,String> hm2 = new HashMap<>();
hm1.put(0,10000000);
hm1.put(1,5000);
hm2.put(0,"xxxx-xxxx-xxxx");
hm2.put(1,"yyyy-yyyy-yyyy");
holder.put("Amt", hm1);
holder.put("Info", hm2);
Iterator<String> iterator = holder.keySet().iterator();
while(iterator.hasNext())
{String key = iterator.next();
System.out.println("key: " + key + " value: " + holder.get(key));
}
Output:
key: Amt value: {0=10000000, 1=5000}
key: Info value: {0=xxxx-xxxx-xxxx, 1=yyyy-yyyy-yyyy}
you can 1st fetch the desired field like Amt using the key1 and then use the key2 (0,1,2....)
for each person to fetch corresponding value.
I am having some difficulty when using Map.putAll(). Instead of updating / adding particular records to my main map, it is overwriting the entries:
ConcurrentMap<String, ConcurrentHashMap<CardType, Card>> cache = new ConcurrentHashMap<String, ConcurrentHashMap<CardType, Card>>();
The three separate maps are generated as below:
ConcurrentMap<String, ConcurrentHashMap<CardType, Card>> businessCardCache = buildBusinesscardCacheValues(connection, getBusinessCards);
ConcurrentMap<String, ConcurrentHashMap<CardType, Card>> personalCardCache = buildPersonalcardCacheValues(connection, getPersonalCards);
ConcurrentMap<String, ConcurrentHashMap<CardType, Card>> socialCardCache = buildSocialcardCacheValues(connection, getSocialCard);
cache.putAll(businessCardCache);
cache.putAll(personalCardCache);
cache.putAll(socialCardCache);
What should happen is user ben for example should be the key and he should have a business a personal and a social card. What in fact happens is he only ends up with a socialCard as I assume it is the last to run and therefore overwrites the previous.
How should I approach modifying this?
Thanks
Your current initialization of cache would cause cache.putAll(personalCardCache); to replace the values added by cache.putAll(businessCardCache); for keys that appear in both maps.
If you want cache to contain all the cards of each user (taken from all 3 input maps), you should initialize it in a different way :
for (String key : businessCardCache.keySet()) {
ConcurrentHashMap<CardType, Card> cards = null;
if (cache.containsKey(key) {
cards = cache.get(key);
} else {
cards = new ConcurrentHashMap<CardType, Card>();
}
cards.putAll (businessCardCache.get(key));
}
Then you do the same for the other 2 maps.