Transform Java List into the Pivot format - java

I have a below class and would like to transform the list of data objects into the pivot table format with java.
public class Data {
private String consultedOn;
private String consultedBy;
// Getters
// Setters
}
List<Data> reports = new ArrayList<Data>();
reports.add(new Data("04/12/2018","Mr.Bob"));
reports.add(new Data("04/12/2018","Mr.Jhon"));
reports.add(new Data("04/12/2018","Mr.Bob"));
reports.add(new Data("05/12/2018","Mr.Jhon"));
reports.add(new Data("06/12/2018","Mr.Bob"));
reports.add(new Data("06/12/2018","Mr.Jhon"));
reports.add(new Data("07/12/2018","Mr.Bob"));
I would like to transform the above list into the below table format with java within a collection.
consultedOn Mr.Bob Mr.Jhon
---------------------------------------
04/12/2018 2 1
05/12/2018 0 1
06/12/2018 1 1
07/12/2018 1 0
Note that the consultedOn field is not restricted to two values, this field may contain any data so that the collection should be dynamic.
I tried using Java8 streams with below code.
class DataMap {
private String consultedOn;
private String consultedBy;
public DataMap(String consultedOn) {
super();
this.consultedOn = consultedOn;
}
public DataMap(String consultedOn, String consultedBy) {
super();
this.consultedOn = consultedOn;
this.consultedBy = consultedBy;
}
public String getConsultedOn() {
return consultedOn;
}
public void setConsultedOn(String consultedOn) {
this.consultedOn = consultedOn;
}
public String getConsultedBy() {
return consultedBy;
}
public void setConsultedBy(String consultedBy) {
this.consultedBy = consultedBy;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((consultedOn == null) ? 0 : consultedOn.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof DataMap ))
return false;
DataMap other = (DataMap )obj;
if (consultedOn == null) {
if (other.consultedOn != null)
return false;
} else if (!consultedOn.equals(other.consultedOn))
return false;
return true;
}
}
Map<DataMap, List<DataReport>> map = reports.stream()
.collect(Collectors.groupingBy(x -> new DataMap(x.getConsultedOn(), x.getConsultedBy())));
But the map is not giving intend results as per my expectations.
I'm not sure how to go-ahead with this kind of data, any help will be appreciated.

Here's a complete answer, using the technique I explained in the comment, i.e. design a class Row representing what you want to generate for each row, i.e. a consultedOn string, and a number of consultations for each person.
public class Pivot {
private static final class Data {
private final String consultedOn;
private final String consultedBy;
public Data(String consultedOn, String consultedBy) {
this.consultedOn = consultedOn;
this.consultedBy = consultedBy;
}
public String getConsultedOn() {
return consultedOn;
}
public String getConsultedBy() {
return consultedBy;
}
}
private static final class Row {
private final String consultedOn;
private final Map<String, Integer> consultationsByPerson = new HashMap<>();
public Row(String consultedOn) {
this.consultedOn = consultedOn;
}
public void addPerson(String person) {
consultationsByPerson.merge(person, 1, Integer::sum);
}
public int getConsultationsFor(String person) {
return consultationsByPerson.getOrDefault(person, 0);
}
public String getConsultedOn() {
return consultedOn;
}
}
private static class PivotReport {
private final Map<String, Row> rowsByConsultedOn = new HashMap<>();
private SortedSet<String> persons = new TreeSet<>();
private PivotReport() {}
private void addData(Data d) {
rowsByConsultedOn.computeIfAbsent(d.getConsultedOn(), Row::new).addPerson(d.getConsultedBy());
persons.add(d.consultedBy);
}
public static PivotReport create(List<Data> list) {
PivotReport report = new PivotReport();
list.forEach(report::addData);
return report;
}
public String toString() {
String headers = "Consulted on\t" + String.join("\t", persons);
String rows = rowsByConsultedOn.values()
.stream()
.sorted(Comparator.comparing(Row::getConsultedOn))
.map(this::rowToString)
.collect(Collectors.joining("\n"));
return headers + "\n" + rows;
}
private String rowToString(Row row) {
return row.getConsultedOn() + "\t" +
persons.stream()
.map(person -> Integer.toString(row.getConsultationsFor(person)))
.collect(Collectors.joining("\t"));
}
}
public static void main(String[] args) {
List<Data> list = createListOfData();
PivotReport report = PivotReport.create(list);
System.out.println(report);
}
private static List<Data> createListOfData() {
List<Data> reports = new ArrayList<Data>();
reports.add(new Data("04/12/2018","Mr.Bob"));
reports.add(new Data("04/12/2018","Mr.Jhon"));
reports.add(new Data("04/12/2018","Mr.Bob"));
reports.add(new Data("05/12/2018","Mr.Jhon"));
reports.add(new Data("06/12/2018","Mr.Bob"));
reports.add(new Data("06/12/2018","Mr.Jhon"));
reports.add(new Data("07/12/2018","Mr.Bob"));
reports.add(new Data("07/12/2018","Mr.Smith"));
return reports;
}
}
Note that since you're using String instead of LocalDate for the consultedOn field, the dates will be sorted lexicographically instead of being sorted chronologically. You should use the appropriate type: LocalDate.

You are probably looking to use Collectors.groupingBy to group the List<DataMap> by consultedOn and further grouping it by consultedBy attribute and their count as :
Map<String, Map<String, Long>> finalMapping = reports.stream()
.collect(Collectors.groupingBy(DataMap::getConsultedOn,
Collectors.groupingBy(DataMap::getConsultedBy,Collectors.counting())));
This would provide you as an output:
{05/12/2018={Mr.Jhon=1}, 06/12/2018={Mr.Jhon=1, Mr.Bob=1},
07/12/2018={Mr.Bob=1}, 04/12/2018={Mr.Jhon=1, Mr.Bob=2}}
Further, if you require all the corresponding consultedBy values to be accounted in, you can create a Set of those from the initial List<DataMap> as :
Set<String> consultedBys = reports.stream()
.map(DataMap::getConsultedBy)
.collect(Collectors.toSet());
using which you can modify your existing map obtained to contain 0 count as well in the following manner:
finalMapping.forEach((k, v) -> consultedBys.forEach(c -> v.putIfAbsent(c, 0L)));
This would now provide you as the output:
{05/12/2018={Mr.Jhon=1, Mr.Bob=0}, 06/12/2018={Mr.Jhon=1, Mr.Bob=1},
07/12/2018={Mr.Jhon=0, Mr.Bob=1}, 04/12/2018={Mr.Jhon=1, Mr.Bob=2}}

The other would be like this:
Map<Pair<String, String>, Integer> map = reports
.stream()
.collect(toMap(data -> new Pair<>(data.getConsultedOn(),
data.getConsultedBy()), data -> 1, Integer::sum));
Map<String, DataMap> result= new HashMap<>();
-
class DataMap {
private String consultedOn;
private Map<String, Integer> map;
}
-
Set<String> persons = new HashSet<>();
persons = reports.stream().map(Data::getConsultedBy).collect(Collectors.toSet());
-
for (Map.Entry<Pair<String, String>, Integer> entry : map.entrySet()) {
Map<String, Integer> val = new HashMap<>();
for (String person : persons) {
if (!person.equals(entry.getKey().getValue()))
val.put(person, 0);
else
val.put(entry.getKey().getValue(), entry.getValue());
}
result.put(entry.getKey().getKey(), new DataMap(entry.getKey().getKey(), val));
}
and final result:
List<DataMap> finalResult = new ArrayList<>(result.values());

Instead of using a separate data structure, you can use a Map of key as consultedOn (date or String) and have the value as a list of (String or your own defined POJO with overridden equals() method.Here in I have used a map like Map<String, List<String>>
All you need is the two methods:
one to set report (addDataToReport) : for each consultedOn (key), create a list of doctors consulted . See comments for map.merge usage
and one to display the data in a report manner (printReport). We are using "%10s" to give proper formatting. Instead of println, format doesn't implicitly append a new line character
Moreover to get the report's column we need to have a set (unique value list), doctors.add(consultedBy); will serve us for this purpose . Java will take care of keeping the doctors' value unique.
public class Application {
Set<String> doctors = new LinkedHashSet<>();
private void addDataToReport(Map<String, List<String>> reportMap, String consultedOn, String consultedBy) {
doctors.add(consultedBy); // set the doctors Set
reportMap.merge(consultedOn, Arrays.asList(consultedBy)// if key = consultedOn is not there add , a new list
, (v1, v2) -> Stream.concat(v1.stream(), v2.stream()).collect(Collectors.toList()));//else merge previous and new values , here concatenate two lists
}
private void printReport(Map<String, List<String>> reportMap) {
/*Set Headers*/
String formatting = "%10s";//give a block of 10 characters for each string to print
System.out.format(formatting, "consultedOn");
doctors.forEach(t -> System.out.format(formatting, t));// print data on console without an implicit new line
System.out.println("\n---------------------------------------");
/*Set row values*/
for (Map.Entry<String, List<String>> entry : reportMap.entrySet()) {
Map<String, Integer> map = new LinkedHashMap<>();
doctors.forEach(t -> map.put(t, 0)); // initialise each doctor count on a day to 0
entry.getValue().forEach(t -> map.put(t, map.get(t) + 1));
System.out.format(formatting, entry.getKey());
map.values().forEach(t -> System.out.format(formatting, t));
System.out.println();
}
}
public static void main(String[] args) {
Application application = new Application();
Map<String, List<String>> reportMap = new LinkedHashMap<>();
String MR_JHON = "Mr.Jhon";
String MR_BOB = "Mr.Bob ";
application.addDataToReport(reportMap, "04/12/2018", MR_BOB);
application.addDataToReport(reportMap, "04/12/2018", MR_JHON);
application.addDataToReport(reportMap, "04/12/2018", MR_BOB);
application.addDataToReport(reportMap, "05/12/2018", MR_JHON);
application.addDataToReport(reportMap, "06/12/2018", MR_BOB);
application.addDataToReport(reportMap, "06/12/2018", MR_JHON);
application.addDataToReport(reportMap, "07/12/2018", MR_BOB);
application.printReport(reportMap);
}
}
Result
consultedOn Mr.Bob Mr.Jhon
---------------------------------------
04/12/2018 2 1
05/12/2018 0 1
06/12/2018 1 1
07/12/2018 1 0

Related

List stream does not filter correct

I have problem with List when I'm streaming. If I reduce stream then I get correct result, but if I filter stream and invoke findFirst() I get empty result. Why? What do I do wrong?
Index - contains data in map:
public class Index {
private final Map<String, String> data = new HashMap<>();
public String getData(String name) {
return data.getOrDefault(name, "");
}
public Set<String> getDataNames() {
return data.keySet();
}
#Override
public String toString() {
return data.toString();
}
}
IndexList - contains Index objects in list, filling is invoke load() method in Main class:
public enum IndexList {
INDICES_0("First list", new LinkedList<>(Arrays.asList("name", "surname", "an")));
private List<Index> loaded;
private final String name;
private final Queue<String> nameQueue;
IndexList(String name, Queue<String> nameQueue) {
this.name = name;
this.nameQueue = nameQueue;
}
public Index get(int id) {
return loaded.get(id-1);
}
public List<Index> getLoaded() {
return loaded;
}
public void load() {
this.loaded = new LinkedList<>();
// ... > loading from xml file
List<Index> loaded = this.loaded;
this.loaded = new ArrayList<>(loaded);
loaded.clear();
}
public Queue<String> queueNames() {
return new LinkedList<>(nameQueue);
}
public String getName() {
return name;
}
}
I normal run I saw some Index object should be show in GUI, but it did not. So I ran program in debugger and added watches.
In debugger:
IndexList.INDICES_0.loaded.size() = 558
IndexList.INDICES_0.loaded.stream().get(0) = {Index#1700} "{surname=Smith, name=John, an=1/2000}"
IndexList.INDICES_0.loaded.stream().reduce((i0, i1) -> i1.getData("surname").equals("Smith") && i1.getData("name").equals("John")? i1 : i0) = {Optional#1623} "Optional[{surname=Smith, name=John, an=1/2000}]"
IndexList.INDICES_0.loaded.stream().filter(i -> i.getData("surname").equals("Smith") && i.getData("name").equals("John")).findFirst() = {Optional#1640} "Optional.empty"
I resolved problem: in set of strings were UTF-8 BOM characters and the same surnames was in different places.
So, reduce method returned the first object in stream.

How to check String equality while iterating over two lists?

I have two java classes:
public class MyClass1 {
private String userId;
private String userName;
private List<CustomList1> customList1;
// getters and setters
// inner CustomList1 class
}
public class MyClass2 {
private String userId;
private List<CustomList2> customList2;
// getters and setters
// inner CustomList2 class
}
Now, I have have lists of these classes:
List<MyClass1> classOneList;
List<MyClass2> classTwoList;
In both classOneList and classTwoList lists, object should be sorted with userId ascending. userId in both lists should have same values. What I want to check is that:
Has both lists same size? If not, thow error exception about.
Has every next element from both list the same userId? If not, throw another exception.
Step 1. I have done with simply if statement.
By prototype, step 2. should look like this:
for (el1, el2 : classOneList, classTwoList) {
el1.getUserId().isEqualTo(el2.getUserId());
}
Try the below code for your problem.
public class Testing {
public static void main(String[] args) {
Map<String, List<String>> map1 = new LinkedHashMap<String, List<String>>();
List<String> m1l1 = new LinkedList<String>();
m1l1.add("One");
m1l1.add("Two");
m1l1.add("Three");
m1l1.add("Four");
map1.put("1", m1l1);
List<String> m1l2 = new LinkedList<String>();
m1l2.add("One");
m1l2.add("Two");
m1l2.add("Three");
m1l2.add("Four");
map1.put("2", m1l2);
// Add more element into the map1 by creating more list.
Map<String, List<String>> map2 = new LinkedHashMap<String, List<String>>();
List<String> m2l1 = new LinkedList<String>();
m2l1.add("One");
m2l1.add("Two");
m2l1.add("Three");
m2l1.add("Four");
map2.put("1", m2l1);
// Add more element into the map2 by creating more list.
for (Entry<String, List<String>> entry : map1.entrySet()) {
if (map2.containsKey(entry.getKey())) {
if (entry.getValue().size() == map2.get(entry.getKey()).size()) {
} else {
System.out.println("UserId are same but list are different for userid: " + entry.getKey());
}
}
else {
System.out.println("Userid '"+entry.getKey()+"' exists in map1 but is not found in map2");
}
}
}
}
Hope this may help you.
if(classOneList.size() != classTwoList.size()){
throw new ErrorException();
}else{
classOneList = classOneList.stream().sorted(Comparator.comparing(MyClass1::getUserId)).collect(Collectors.toList());
classTwoList = classTwoList.stream().sorted(Comparator.comparing(MyClass2::getUserId)).collect(Collectors.toList());
for (int i = 0; i < classOneList.size(); i++){
if(!classOneList.get(i).getUserId().equals(classTwoList.get(i).getUserId())){
throw new AnotherErrorException();
}
}
}

Stream Collection to other structure

I try convert list objects of Dictionary to object with contains list.
public class Dictionary {
private String dictCode;
private String dictName;
private String dictDescription;
private String dictElemCode;
private String dictElemName;
private String dictElemDescription;
}
//parent
public class DictDTO {
private String code;
private String value;
private String description;
private List<DictElemDTO> listDictElemDTO;
}
//children
public class DictElemDTO {
private String code;
private String value;
private String description;
}
Example data for Dictionary class:
Dictionary d1 = new Dictionary("a1", "dict1", "desc1", "elem_code_1", "elem_code_name", "elem_code_desc");
Dictionary d2 = new Dictionary("a1", "dict1", "desc1", "elem_code_2", "elem_code_name2", "elem_code_desc2");
Dictionary d3 = new Dictionary("a2", "dict2", "desc2", "elem_code_3", "elem_code_name3", "elem_code_desc3");
And the result should by like this:
a1
------ elem_code_1
------ elem_code_2
a2
------ elem_code_3
My solution for stream works but it's slow because I use stream of list more than once.
public static void main(String[] args) {
Dictionary d1 = new Dictionary("a1", "dict1", "desc1", "elem_code_1", "elem_code_name", "elem_code_desc");
Dictionary d2 = new Dictionary("a1", "dict1", "desc1", "elem_code_2", "elem_code_name2", "elem_code_desc2");
Dictionary d3 = new Dictionary("a2", "dict2", "desc2", "elem_code_3", "elem_code_name3", "elem_code_desc3");
List<Dictionary> list = ImmutableList.of(d1, d2, d3);
List<DictDTO> newList = list.stream().filter(distinctByKey(Dictionary::getDictCode)).map(t -> {
DictDTO dto = new DictDTO();
dto.setCode(t.getDictCode());
dto.setValue(t.getDictName());
dto.setDescription(t.getDictDescription());
dto.setListDictElemDTO(
list.stream().filter(e -> e.getDictCode().equals(t.getDictCode())).map(w -> {
DictElemDTO elemDto = new DictElemDTO();
elemDto.setCode(w.getDictElemCode());
elemDto.setValue(w.getDictElemName());
elemDto.setDescription(w.getDictElemDescription());
return elemDto;
}).collect(Collectors.toList())
);
return dto;
}).collect(Collectors.toList());
for (DictDTO dto : newList) {
System.err.println(dto.getCode());
for (DictElemDTO dtoE : dto.getListDictElemDTO()) {
System.err.println("------ " + dtoE.getCode());
}
}
}
static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Map<Object, Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
What is better approach for this problem using stream in Java 8?
This looks like a job for Collectors.groupingBy:
Map<String,List<DictElemDTO>>
map = Stream.of(d1,d2,d3)
.collect(Collectors.groupingBy(Dictionary::getDictCode,
Collectors.mapping(d-> new DictElemDTO (d.getDictElemCode(),d.getDictElemName(),d.getDictElemDescription()),
Collectors.toList())));
This will give you a mapping of dictionary codes to the corresponding list of DictElemDTOs.
It requires a bit more work to create the DictDTO objects.

Java 8 Lambda Collectors.summingLong multiple columns?

I have POJO definition as follows:
class EmployeeDetails{
private String deptName;
private Double salary;
private Double bonus;
...
}
Currently, i have lambda expression for Group By 'deptName' as :
$set.stream().collect(Collectors.groupingBy(EmployeeDetails::getDeptName,
Collectors.summingLong(EmployeeDetails::getSalary));
Question Is it possible to Sum more than one column? I need to compute sum on both fields salary and bonus in one expression instead of multiple times?
SQL representation would be:
SELECT deptName,SUM(salary),SUM(bonus)
FROM TABLE_EMP
GROUP BY deptName;
You need to create an additional class that will hold your 2 summarised numbers (salary and bonus). And a custom collector.
Let's say you have
private static final class Summary {
private double salarySum;
private double bonusSum;
public Summary() {
this.salarySum = 0;
this.bonusSum = 0;
}
#Override
public String toString() {
return "Summary{" +
"salarySum=" + salarySum +
", bonusSum=" + bonusSum +
'}';
}
}
for holding sums. Then you need a collector like this:
private static class EmployeeDetailsSummaryCollector implements Collector<EmployeeDetails, Summary, Summary> {
#Override
public Supplier<Summary> supplier() {
return Summary::new;
}
#Override
public BiConsumer<Summary, EmployeeDetails> accumulator() {
return (summary, employeeDetails) -> {
summary.salarySum += employeeDetails.salary;
summary.bonusSum += employeeDetails.bonus;
};
}
#Override
public BinaryOperator<Summary> combiner() {
return (summary, summary1) -> {
summary.salarySum += summary1.salarySum;
summary.bonusSum += summary1.bonusSum;
return summary;
};
}
#Override
public Function<Summary, Summary> finisher() {
return Function.identity();
}
#Override
public Set<Characteristics> characteristics() {
return EnumSet.of(Collector.Characteristics.IDENTITY_FINISH);
}
}
With these classes you can collect your results like
final List<EmployeeDetails> employees = asList(
new EmployeeDetails(/* deptName */"A", /* salary */ 100d, /* bonus */ 20d),
new EmployeeDetails("A", 150d, 10d),
new EmployeeDetails("B", 80d, 5d),
new EmployeeDetails("C", 100d, 20d)
);
final Collector<EmployeeDetails, Summary, Summary> collector = new EmployeeDetailsSummaryCollector();
final Map<String, Summary> map = employees.stream()
.collect(Collectors.groupingBy(o -> o.deptName, collector));
System.out.println("map = " + map);
Which prints this:
map = {A=[salary=250.0, bonus=30.0], B=[salary=80.0, bonus=5.0], C=[salary=100.0, bonus=20.0]}
I know you've got your answer, but here is my take(I was writing while the other was posted). There is already a Pair in java in the form of AbstractMap.SimpleEntry.
System.out.println(Stream.of(new EmployeeDetails("first", 50d, 7d), new EmployeeDetails("first", 50d, 7d),
new EmployeeDetails("second", 51d, 8d), new EmployeeDetails("second", 51d, 8d))
.collect(Collectors.toMap(EmployeeDetails::getDeptName,
ed -> new AbstractMap.SimpleEntry<>(ed.getSalary(), ed.getBonus()),
(left, right) -> {
double key = left.getKey() + right.getKey();
double value = left.getValue() + right.getValue();
return new AbstractMap.SimpleEntry<>(key, value);
}, HashMap::new)));
Grouping by is a terminal operation that yields a map. The map produced by the groupingBy in the code below is a Map<String, List<EmployeeDetails>>. I create a new stream using the Map entrySet method. I then create a new Map using Collectors.toMap. This approach uses method chaining to avoid creating another class and create more concise code.
details.stream()
.collect(Collectors.groupingBy(EmployeeDetails::getDeptName))
.entrySet()
.stream()
.collect(Collectors.toMap(x->x.getKey(), x->x.getValue()
.stream()
.mapToDouble(y -> y.getSalary() + y.getBonus())
.sum()));

Finding an object from list inside a map

This is my first question in Stackoverflow.I have come to find a issue with one of the problem suggested and give to me by my colleague to do some research on it.
My question is
i have a class
Class Function{
String func;
String funcname;
boolean log;
}
i have created some objects:
obj1 : ("a" ,"b",true)- //these values come from either DB or UI
obj2 : ("c" ,"x",true)
obj3 : ("a" ,"z",true)
i have a list:
List<function> flist;
now i want to have that list in the map and want to put in inside the map
Map<String, List<function>> funcMap
and then display this following output:
a:[obj1 obj3]
b:[obj2]
if i have the list but how to go about and find the above output as desired
Try this,
add all the objects in the flist.
initialize the map
Map<String, List<Function>> funcMap = new HashMap<String, List<Function>>();
going to add the object to the relevant key based on the func value the object will add to the value list.
for (Function functionValue : flist)
{
List<Function> functionList = funcMap.get(functionValue.getFunc());
if (functionList != null && !functionList.isEmpty())
{
functionList.add(functionValue);
}
else
{
functionList = new ArrayList<Function>();
functionList.add(functionValue);
funcMap.put(functionValue.getFunc(), functionList);
}
}
Atlast print the funcMap
for (Map.Entry< String, List<Function>> entry : funcMap.entrySet())
{
System.out.println("Key : " + entry.getKey() + "Values : "+entry.getValue());
}
Hmm.. I think it's a case of parsing your list in a nested loop kind of way. Here is the pseudo-code:
public void listToMap(List<Function> list)
{
Map<String, List<Function>> map := new Map
for every function in the list.
{
if(is the current function's func value does not exist in the map)
{
func := current functions func value
List matchingFunctions := new list of Functions.
for(every function in the list.)
{
// Every Function with the same key get's added to a list.
if(function has the same func value as func)
{
add to matchingFunctions.
}
}
// That list and key get put into the HashMap.
map.put(func, matchingFunctions).
}
}
}
A Note on your code design
Java convention states that you should wrap your member objects up in getters and setters, and that those members should be private.
what about:
public class FuncTest {
public static void main(String[] args) {
new FuncTest().start();
}
private void start() {
List<Function> flist = new ArrayList<Function>();
flist.add(new Function("a", "b", true));
flist.add(new Function("c", "x", true));
flist.add(new Function("a", "z", true));
Map<String, List<Function>> funcMap = new HashMap<String, List<Function>>();
for (Function func : flist) {
this.add(func.func, func, funcMap);
this.add(func.funcname, func, funcMap);
}
}
private void add(String field, Function func, Map<String, List<Function>> funcMap) {
List<Function> subList = funcMap.get(field);
if (subList == null) {
subList = new ArrayList<Function>();
funcMap.put(field, subList);
}
subList.add(func);
}
}
Note
As already mentioned by Chris you should think about your code design. Use getters and setters ..
public class Stackoverflow {
public static void main(String[] args) {
Function obj1 = new Function("a" ,"b",true);
Function obj2 = new Function("c" ,"x",true);
Function obj3 = new Function("a" ,"z",true);
List<Function> functionsList1 = new ArrayList<Function>();
functionsList1.add(obj1);
functionsList1.add(obj3);
List<Function> functionsList2 = new ArrayList<Function>();
functionsList2.add(obj2);
Map<String, List<Function>> funcMap = new LinkedHashMap<String, List<Function>>();
funcMap.put("a", functionsList1);
funcMap.put("b", functionsList2);
Set<Entry<String,List<Function>>> entrySet = funcMap.entrySet();
for (Entry<String, List<Function>> entry : entrySet) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
}
}
class Function {
String func;
String funcname;
boolean log;
public Function(String func, String funcname, boolean log) {
super();
this.func = func;
this.funcname = funcname;
this.log = log;
}
#Override
public String toString() {
return "Function [func=" + func + ", funcname=" + funcname + ", log="
+ log + "]";
}
}
Write your own map.
Pass the list to map, let map will decide what portion of list to keep as value.
I have added put method here, like the same, have to Override other methods.
class MyHashMap<K,V> extends HashMap<K,V>{
#SuppressWarnings("unchecked")
public V put(K k, V v) {
String key = (String)k;
List<Function> list = (List<Function>) v;
List<Function> list2 = new ArrayList<Function>();
for (Function function : list) {
if(key.equalsIgnoreCase(function.func)){
list2.add(function);
}
}
return (V) list2;
};
#Override
public boolean equals(Object o) {
// Your own code
return true;
}
// other methods goes here..
}

Categories