Java数组重复元素统计及Firebase实时数据库当日记录数查询问题
Java统计数组内重复元素出现次数实现方案
核心逻辑是通过哈希表存储元素与对应出现次数,示例代码如下:
import java.util.HashMap; import java.util.Map; public class ArrayDuplicateCount { public static void main(String[] args) { // 示例数组,可替换为任意类型数组 String[] arr = {"a", "b", "a", "c", "b", "a", "d"}; Map<String, Integer> countMap = new HashMap<>(); for (String item : arr) { // 元素已存在则计数+1,不存在则初始化为1 countMap.put(item, countMap.getOrDefault(item, 0) + 1); } // 遍历输出统计结果 for (Map.Entry<String, Integer> entry : countMap.entrySet()) { System.out.printf("元素%s出现次数:%d%n", entry.getKey(), entry.getValue()); } } }
如果使用Java 8及以上版本,可以用流式写法简化代码:
import java.util.Arrays; import java.util.stream.Collectors; import java.util.Map; Map<String, Long> countMap = Arrays.stream(arr) .collect(Collectors.groupingBy(item -> item, Collectors.counting()));
Firebase Realtime Database当日记录统计问题修复
问题根因
- 版本兼容问题:
LocalDate.now()仅支持Android API 26及以上系统,低版本设备上currDate为空,无法匹配日期 - 统计逻辑错误:每次遍历子节点都会重新创建日期列表,只要列表中存在当日日期就直接将整个列表长度作为统计值,会把其他日期的条目也计入结果
- 冗余操作:在循环内反复创建
SimpleDateFormat实例,无意义消耗性能 - 效率问题:全量拉取所有节点数据再过滤,数据量大时性能极差,可通过Firebase查询能力直接过滤符合条件的节点
方案1:修复现有遍历逻辑
private void fetchDataWaterCount() { String uid = firebaseAuth.getUid(); if (uid == null) return; // 兼容所有Android版本的当日日期格式化 SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd", Locale.US); String currDate = dateFormatter.format(new Date()); int waterCount = 0; waterRef = FirebaseDatabase.getInstance().getReference("Users").child(uid).child("body").child("water"); waterRef.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { if (snapshot.exists()) { for (DataSnapshot ds : snapshot.getChildren()) { WaterModel waterModel = ds.getValue(WaterModel.class); if (waterModel == null) continue; long timeStamp = waterModel.getDate(); String itemDate = dateFormatter.format(new Date(timeStamp)); if (currDate.equals(itemDate)) { waterCount++; } } // 统计完成后统一更新UI updateWaterProgress(waterCount); } } @Override public void onCancelled(@NonNull DatabaseError error) { // 建议添加错误处理逻辑 } }); } // 单独抽取UI更新逻辑,避免代码冗余 private void updateWaterProgress(int waterCount) { progressBar.setMax(12); progressBar.setProgress(waterCount); progressBar.setSecondaryProgress(waterCount); if (waterCount >= 12) { textViewWaterCount.setText("Done"); textViewWaterCount.setTextColor(getResources().getColor(R.color.colorGreen_900)); progressBar.setProgressDrawable(getActivity().getDrawable(R.drawable.circut_progressbar_green)); } else { textViewWaterCount.setText(String.valueOf(waterCount)); progressBar.setProgressDrawable(getActivity().getDrawable(R.drawable.circut_progress_bar)); } }
方案2:优化查询效率(推荐)
直接通过时间戳范围查询,无需拉取全量数据,性能更高:
private void fetchDataWaterCountOptimized() { String uid = firebaseAuth.getUid(); if (uid == null) return; // 计算今日0点和明日0点的时间戳 Calendar calendar = Calendar.getInstance(); // 今日0点 calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); long startTime = calendar.getTimeInMillis(); // 明日0点 calendar.add(Calendar.DAY_OF_MONTH, 1); long endTime = calendar.getTimeInMillis(); waterRef = FirebaseDatabase.getInstance().getReference("Users").child(uid).child("body").child("water"); // 直接查询date字段在今日时间范围内的节点 waterRef.orderByChild("date").startAt(startTime).endAt(endTime - 1) .addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { int waterCount = (int) snapshot.getChildrenCount(); updateWaterProgress(waterCount); } @Override public void onCancelled(@NonNull DatabaseError error) { // 建议添加错误处理逻辑 } }); }
内容的提问来源于stack exchange,提问作者Nikita Alekseev
相关产品推荐
相关产品推荐

