승기유
승기유

Reputation: 133

Which data structure should be used in Java

Assuming that there are three variables, "staffId", "subject" and "sessionTime"

and the examples are:

<9600001, info2001, Tue3>,
<9600001, info2002, Wed4>,
<9600002, info2001, Wed2>,
<9600001, info2001, Thu9>,
<9600001, info2003, Fri10>,
<9600002, info2004, Wed4>

Finally the output should be:

STAFF_ID HOURS
 9600002 4
 9600001 7

Calculation: Observe that staff 9600001 has 4 actual sessions, and is involved in 3 different subjects, so this makes 4+3=7 hours in total.

To code this question, I decided to use nested HashMap, like

Map<Integer, Map<String, String>> submission = new HashMap<Integer, TreeMap<String, String>>();

but the problem was that, the tree-map replaces its previous value as the value has to be unique. For example, when I put

<9600001, info2001, Tue3> and <9600001, info2001, Thu9> into the map,

in the hash-map, there should be

9600001, info2001 - Tue3 and Thu9

but the previous value is replaced so there is only one value existing:

9600001, info2001 - Thu9

Can someone please tell me how to approach to this question?

Which data structures should I use?

Upvotes: 1

Views: 153

Answers (4)

Lu Fangjian
Lu Fangjian

Reputation: 59

Though the counting formula is a bit strange (count distinct subject + count sessionTime), I guess what you meant was Map<Integer, Map<String, List<String>>>. I've come up with 2 methods, please modify if necessary.

public class Dummy {

    public Map<Integer, Integer> countHours(List<Submission> submissions) {

        Map<Integer, Integer> res = new HashMap<>();
        Map<Integer, Set<String>> subjectMap = new HashMap<>();
        Map<Integer, List<String>> sessionTimeMap = new HashMap<>();

        for (Submission s : submissions) {
            subjectMap.computeIfAbsent(s.getStaffId(), v -> new HashSet<>()).add(s.getSubject());
            sessionTimeMap.computeIfAbsent(s.getStaffId(), v -> new ArrayList<>()).add(s.getSessionTime());
        }

        for (Map.Entry<Integer, Set<String>> e : subjectMap.entrySet()) {
            res.put(e.getKey(), e.getValue().size());
        }

        for (Map.Entry<Integer, List<String>> e : sessionTimeMap.entrySet()) {
            res.merge(e.getKey(), e.getValue().size(), Integer::sum);
        }

        return res;
    }

    public Map<Integer, Integer> countHours2(List<Submission> submissions) {

        Map<Integer, Map<String, Long>> collect = submissions.stream()
                .collect(Collectors.groupingBy(Submission::getStaffId,
                        Collectors.groupingBy(Submission::getSubject, Collectors.counting())));

        return collect.entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey,
                        e -> e.getValue().size() +
                                e.getValue().values().stream().mapToInt(Number::intValue).sum()));
    }

    @Test
    public void test() {

        List<Submission> submissions = new ArrayList<>();
        submissions.add(new Submission(9600001, "info2001", "Tue3"));
        submissions.add(new Submission(9600001, "info2002", "Wed4"));
        submissions.add(new Submission(9600002, "info2001", "Wed2"));
        submissions.add(new Submission(9600001, "info2001", "Thu9"));
        submissions.add(new Submission(9600001, "info2003", "Fri10"));
        submissions.add(new Submission(9600002, "info2004", "Wed4"));

        System.out.println(countHours(submissions)); // {9600002=4, 9600001=7}

        System.out.println(countHours2(submissions)); // {9600002=4, 9600001=7}
    }

}

// In case you have lombok
@Data
@AllArgsConstructor
class Submission {

    private int staffId;
    private String subject;
    private String sessionTime;

    // In case you do not have lombok

//    Submission(int staffId, String subject, String sessionTime) {
//        this.staffId = staffId;
//        this.subject = subject;
//        this.sessionTime = sessionTime;
//    }
//
//    public int getStaffId() {
//        return staffId;
//    }
//
//    public void setStaffId(int staffId) {
//        this.staffId = staffId;
//    }
//
//    public String getSubject() {
//        return subject;
//    }
//
//    public void setSubject(String subject) {
//        this.subject = subject;
//    }
//
//    public String getSessionTime() {
//        return sessionTime;
//    }
//
//    public void setSessionTime(String sessionTime) {
//        this.sessionTime = sessionTime;
//    }

}

Upvotes: 0

sprinter
sprinter

Reputation: 27996

Java is an object oriented language so you are best off making classes to represent the items you want to record and manipulate. In your case there are staff, subjects and sessions:

class Staff {
    private final String id;
}

class Subject {
    private final String id;
}

class Session {
    private final Staff staff;
    private final Subject subject;
    int period;
}

If you have a list of sessions then you can fairly easily generate a map from staff to sum of period (for example):

List<Session> sessions;

Map<Staff, Integer> staffTotalTime = sessions.stream()
    .collect(groupingBy(Session::getStaff, summingInt(Session::getPeriod));

My recommendation is to not start by modelling data to optimise access. Form data structures that are a simple and elegant representation of the relationships between the objects and then manipulate it into other forms when required. It would be trivial to change the statement above to sum by subject or create an average or just about anything else without having to change the data model you use to store the objects.

Upvotes: 0

Shubhendu Pramanik
Shubhendu Pramanik

Reputation: 2751

You need to create a custom object and a Map for this problem.

Map<Integer, CustomObject> map = new HashMap<Integer, CustomObject>();

and

class CustomObject {
    int staffIdCount; //Number of distinct staffId records (e.g. for 9600001 value will be 4)
    Set<String> subject = new HashSet<String>(); //distinct subjects
}

Functionality will be like below:

when you encounter 9600001 perform below operation

    if(map.containsKey(9600001))
    {
        CustomObject tmp = map.get(9600001);
        tmp.staffIdCount+=1;
        tmp.subject.add("info2001"); //the corresponding subject
        map.put(9600001, tmp);
    }
    else
    {
        CustomObject tmp = new CustomObject();
        tmp.staffIdCount +=1;
        tmp.subject.add("info2001");

        map.put(9600001, tmp);
    }

EDIT: so staffIdCount will give you number of staffIds and size of subject will give you distinct count of subject

Upvotes: 0

mleko
mleko

Reputation: 12243

Use List of records.

class Record {
  int staffId;
  String subject;
  String sessionTime;
}

List<Record> submissions = new ArrayList<>();

or Map of List

class Record {
  String subject;
  String sessionTime;
}

Map<Integer, List<Record>> submissions = new HashMap<>();

Upvotes: 3

Related Questions