如何根据Firebase中不同的子项在Android中获取数据的总和

huangapple go评论76阅读模式
英文:

How to get total of data based on different child from Firebase in Android

问题

Calendar mCalendar = Calendar.getInstance();
int year = mCalendar.get(Calendar.YEAR);
int month = mCalendar.get(Calendar.MONTH);
final int[] Currmonth = {month + 1};         
int lastDay = mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH);
int firstDay = 1;
String start = year + "-" + Currmonth[0] + "-" + firstDay;
String end = year + "-" + Currmonth[0] + "-" + lastDay;
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("Users Mood");
Query range = ref.child(user.getUid()).orderByChild("Date").startAt(start).endAt(end);
range.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        Map<String, Double> courseTotalMap = new HashMap<>();
        
        for (DataSnapshot ds : dataSnapshot.getChildren()) {
            String course = ds.child("Course").getValue(String.class);
            String scale = ds.child("Scale").getValue(String.class);
            double num = 0;
            
            if (scale.equals("3")) {
                num = 0.6;
            } else if (scale.equals("2")) {
                num = 0.4;
            } else if (scale.equals("4")) {
                num = 0.8;
            }
            
            if (courseTotalMap.containsKey(course)) {
                double total = courseTotalMap.get(course) + num;
                courseTotalMap.put(course, total);
            } else {
                courseTotalMap.put(course, num);
            }
        }
        
        for (String key : courseTotalMap.keySet()) {
            Log.d("tag", key + courseTotalMap.get(key));
        }
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {

    }
});

请注意,我已经纠正了逻辑错误,将数据存储在courseTotalMap中,使用课程名称作为键,将相应的总分数累加到映射值中。这样,您将得到每个课程的总分数。

英文:

There are multiples dates and data (Course and Scale) for each date. Each date and data store under a unique key. The dates are inserted by Date picker.

&quot;Data&quot;:{
&quot;K2ngvpioRUYF4bRM07Da5cbAjE53&quot;:{   //UID
&quot;-M3jNjCuGdMCwt1Czpwz&quot;:{        //unique key
&quot;Date&quot;:&quot;2020-3-30&quot;,
&quot;Course&quot;:&quot;A&quot;,
&quot;Scale&quot;:&quot;3&quot;
},
&quot;-M5hxnQrCJdCUvRcMZJu&quot;:{
&quot;Date&quot;:&quot;2020-4-24&quot;,
&quot;Course&quot;:&quot;A&quot;,
&quot;Scale&quot;:&quot;3&quot;
}
&quot;-M3jQWxm7z0EQYgkVenX&quot;:{
&quot;Date&quot;:&quot;2020-4-29&quot;,
&quot;Course&quot;:&quot;B&quot;,
&quot;Scale&quot;:&quot;4&quot;
},
&quot;-M5hxn-rCJICUvRcMZJu&quot;:{
&quot;Date&quot;:&quot;2020-4-24&quot;,
&quot;Course&quot;:&quot;B&quot;,
&quot;Scale&quot;:&quot;2&quot;
}
}
}

I would like to calculate the total number of scales based on Course monthly. For scale, if the number is 3, it means 0.6. If the number is 2, it means 0.4. If the number is 4, it means 0.8. So, for the Course A, the total number is 1.2(0.6+0.6). For Course B, the total number is 1.2 (0.8+0.4).

   Calendar mCalendar = Calendar.getInstance();
int year = mCalendar.get(Calendar.YEAR);
int month = mCalendar.get(Calendar.MONTH);
final int[] Currmonth = {month + 1};         //this is array because there are other method using this but unnecessary for this question
int lastDay = mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH);
int firstDay=1;
String start=year+&quot;-&quot;+Currmonth[0]+&quot;-&quot;+firstDay;
String end=year+&quot;-&quot;+Currmonth[0]+&quot;-&quot;+lastDay;
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child(&quot;Users Mood&quot;);
Query range = ref.child(user.getUid()).orderByChild(&quot;Date&quot;).startAt(start).endAt(end);
range.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
ArrayList&lt;String&gt; courses=new ArrayList&lt;&gt;();
Map&lt;String, Double&gt; hm = new HashMap&lt;&gt;();
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String course=ds.child(&quot;Course&quot;).getValue(String.class);
courses.add(course);
String scale=ds.child(&quot;Scale&quot;).getValue(String.class);
for(String i :courses) {
double num=0;
if (hm.get(i).equals(&quot;1&quot;)) {
num=0.2;
}else if(hm.get(i).equals(&quot;2&quot;)){
num=0.4;
}else if(hm.get(i).equals(&quot;3&quot;)){
num=0.6;
}else if(hm.get(i).equals(&quot;4&quot;)){
num=0.8;
}else if(hm.get(i).equals(&quot;5&quot;)){
num=1;
}
double total = hm.containsKey(course) ? hm.get(course) : 0;
total += num;
hm.put(course, total);
}
}
for(String key:hm.keySet()) {
Log.d(&quot;tag&quot;, key+hm.get(key));
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});

In this case, the query is from the start date of month to end date of the month. The logic for mapping two children is incorrect. I don't think hashmap is suitable for this case because there might be few data with the same course with same scale (For example, there are two same data, Course A with scale 3 or num 0.6). Please help me to correct my logic.

答案1

得分: 1

你使用日期的方式并不是很高效。因为这意味着 2020-4-12 会排在 2020-4-4 之前。我建议

//year 是整数年份
String monthStr = month; //month 是整数月份
if(month <= 9) monthStr = "0" + monthStr;
String dateStr = date; //date 是整数日期
if(date <= 9) dateStr = "0" + dateStr;
String finalStr = year + "-" + monthStr + "-" + dateStr;

话虽如此,你不必要地使用了一个 ArrayList。与你所说的相反,这里可以使用 HashMap。
而且 hm.get(i) 会返回一个 Double,我不知道你为什么要将其与一个字符串进行比较,当实际上你应该比较字符串刻度。无论如何,看看我对你的循环体所做的修改。我希望你知道 parseDouble,它可以将一个字符串转换为对应的 Double 值。

for(DataSnapshot ds : dataSnapshot.getChildren()) {
    String course = ds.child("Course").getValue(String.class);
    String scale = ds.child("Scale").getValue(String.class);

    double num = Double.parseDouble(scale) / 5.0;

    double total = hm.containsKey(course) ? hm.get(course) : 0;
    total += num;
    hm.put(course, total);
}

for(String key : hm.keySet()) {
    Log.d("tag", key + hm.get(key));
}

如果你有任何疑问,请随意提问。

英文:

The way you are using your date is not very efficient. Because that would mean 2020-4-12 comes before 2020-4-4. I suggest

//year is integer year
String monthStr = month; //month is integer month
if(month&lt;=9)monthStr=&quot;0&quot;+monthStr;
String dateStr = date; //date is integer date
if(date&lt;=9)dateStr=&quot;0&quot;+dateStr;
String finalStr = year+&quot;-&quot;+monthStr+&quot;-&quot;+dateStr;

Now that being said, You are using an ArrayList unnecessarily. On contrary to what you said the HashMap can be used here.
Also hm.get(i) would return Double and I dont know why you are comparing it to a string, when you should actually be comparing the string scale. Anyway, Look at this modification I made to your loop body. I hope you know parseDouble which converts a String to its Double equivalent.

for(DataSnapshot ds : dataSnapshot.getChildren()) {
String course=ds.child(&quot;Course&quot;).getValue(String.class);
String scale=ds.child(&quot;Scale&quot;).getValue(String.class);
double num= Double.parseDouble(scale)/5.0;
double total = hm.containsKey(course) ? hm.get(course) : 0;
total += num;
hm.put(course, total);
}
for(String key:hm.keySet()) {
Log.d(&quot;tag&quot;, key+hm.get(key));
}

If you have any doubts fell free to comment.

huangapple
  • 本文由 发表于 2020年5月3日 23:55:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/61577439.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定