如何将嵌套的地图结构中的周数据转换为月度数据

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

How do I convert weekly data to a monthly data from a nested map structure

问题

import java.util.*;
import java.util.stream.Collectors;

public class WeeklyToMonthlyConverter {
    public static Map<String, Map<String, Object>> convertToMonthlyData(Map<String, Map<String, Object>> weeklyData) {
        return weeklyData.entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        entry -> entry.getValue().entrySet().stream()
                                .collect(Collectors.groupingBy(
                                        weekEntry -> weekEntry.getKey().substring(0, 7),
                                        Collectors.toMap(
                                                Map.Entry::getKey,
                                                Map.Entry::getValue,
                                                WeeklyToMonthlyConverter::sumData
                                        )
                                ))
                ));
    }

    private static Map<String, Object> sumData(Map<String, Object> targetMap, Map<String, Object> sourceMap) {
        for (Map.Entry<String, Object> entry : sourceMap.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();

            if (value instanceof Number) {
                if (targetMap.containsKey(key)) {
                    Number existingValue = (Number) targetMap.get(key);
                    double sum = existingValue.doubleValue() + ((Number) value).doubleValue();
                    targetMap.put(key, sum);
                } else {
                    targetMap.put(key, value);
                }
            }
        }
        return targetMap;
    }

    public static void main(String[] args) {
        // ... (rest of your code remains the same)
    }

    private static Map<String, Object> createWeeklyObject(int productSales, int noOfUnitsSold, int customerViews, double conversion) {
        // ... (rest of your code remains the same)
    }
}

这里是使用 lambda 和 streams 重写了你的 convertToMonthlyData 方法。这个版本更为简洁,但实现的功能与之前的版本相同。

英文:

I have a some data in Java which is in the format Map&lt;String, Map&lt;String, Object&gt;&gt;

Let's say we have 2 countries and also assume that we have weekly data for each country, which means the last 60 days will have a data of something like this:

   {
&quot;US”= {
&quot;2023-01-02”={
&quot;customerViews&quot;= 2500,
&quot;productSales&quot;= 1200,
&quot;noOfUnitsSold&quot;= 600,
&quot;conversion&quot;= 0.24
},
&quot;2023-01-09”={
&quot;customerViews&quot;= 2900,
&quot;productSales&quot;= 1400,
&quot;noOfUnitsSold&quot;= 700,
&quot;conversion&quot;= 0.24
},
&quot;2023-01-16”= {
&quot;customerViews&quot;= 2000,
&quot;productSales&quot;= 1000,
&quot;noOfUnitsSold&quot;= 500,
&quot;conversion&quot;= 0.25
},
&quot;2023-02-23”= {
&quot;customerViews&quot;= 2700,
&quot;productSales&quot;= 1300,
&quot;noOfUnitsSold&quot;= 650,
&quot;conversion&quot;= 0.22
},
&quot;2023-01-30”={
&quot;customerViews&quot;= 1800,
&quot;productSales&quot;= 900,
&quot;noOfUnitsSold&quot;= 450,
&quot;conversion&quot;= 0.21
},
&quot;2023-02-06”= {
&quot;customerViews&quot;= 2300,
&quot;productSales&quot;= 1100,
&quot;noOfUnitsSold&quot;= 550,
&quot;conversion&quot;= 0.23
},
&quot;2023-02-13”= {
&quot;customerViews&quot;= 2000,
&quot;productSales&quot;= 1000,
&quot;noOfUnitsSold&quot;= 500,
&quot;conversion&quot;= 0.25
},
&quot;2023-02-20”= {
&quot;customerViews&quot;= 2500,
&quot;productSales&quot;= 1200,
&quot;noOfUnitsSold&quot;= 600,
&quot;conversion&quot;= 0.24
}
},
&quot;CA”= {
&quot;2023-01-02”= {
&quot;customerViews&quot;= 2000,
&quot;productSales&quot;= 1000,
&quot;noOfUnitsSold&quot;= 500,
&quot;conversion&quot;= 0.24
},
&quot;2023-01-23”= {
&quot;customerViews&quot;= 2200,
&quot;productSales&quot;= 1100,
&quot;noOfUnitsSold&quot;= 550,
&quot;conversion&quot;= 0.22
},
&quot;2023-01-30”={
&quot;customerViews&quot;= 1800,
&quot;productSales&quot;= 900,
&quot;noOfUnitsSold&quot;= 450,
&quot;conversion&quot;= 0.22
},
&quot;2023-02-06”= {
&quot;customerViews&quot;= 1700,
&quot;productSales&quot;= 850,
&quot;noOfUnitsSold&quot;= 425,
&quot;conversion&quot;= 0.21
},
&quot;2023-02-13”= {
&quot;customerViews&quot;= 2000,
&quot;productSales&quot;= 1000,
&quot;noOfUnitsSold&quot;= 500,
&quot;conversion&quot;= 0.24
}
}
}

The reason I didn't include few weeks of data for 2nd country is because, there might be a case where there are no data for that week. So in that case there will be no entries for that week.

Now, I want to take this data as a input and convert to a monthly data which in turn the response looks like this:

    {
&quot;US&quot;= {
&quot;2023-01&quot;= {
&quot;customerViews&quot;= 12400.0,
&quot;productSales&quot;= 6000.0,
&quot;noOfUnitsSold&quot;= 3000.0,
&quot;conversion&quot;= 1.18
},
&quot;2023-02&quot;= {
&quot;customerViews&quot;= 6300.0,
&quot;productSales&quot;= 3100.0,
&quot;noOfUnitsSold&quot;= 1550.0,
&quot;conversion&quot;= 0.7
}
},
&quot;CA&quot;= {
&quot;2023-01&quot;= {
&quot;customerViews&quot;= 4150.0,
&quot;productSales&quot;= 2050.0,
&quot;noOfUnitsSold&quot;= 1025.0,
&quot;conversion&quot;= 0.45
},
&quot;2023-02&quot;= {
&quot;customerViews&quot;= 3500.0,
&quot;productSales&quot;= 1750.0,
&quot;noOfUnitsSold&quot;= 875.0,
&quot;conversion&quot;= 0.43
}
}
}

This is what I tried:

   import java.util.*;
public class WeeklyToMonthlyConverter {
public static Map&lt;String, Map&lt;String, Object&gt;&gt; convertToMonthlyData(Map&lt;String,   Map&lt;String, Object&gt;&gt; weeklyData) {
Map&lt;String, Map&lt;String, Object&gt;&gt; monthlyData = new HashMap&lt;&gt;();
for (Map.Entry&lt;String, Map&lt;String, Object&gt;&gt; countryEntry : weeklyData.entrySet()) {
String countryId = countryEntry.getKey();
Map&lt;String, Object&gt; weeklyMap = countryEntry.getValue();
Map&lt;String, Object&gt; monthlyMap = new HashMap&lt;&gt;();
for (Map.Entry&lt;String, Object&gt; weekEntry : weeklyMap.entrySet()) {
String weekDate = weekEntry.getKey();
Object weekData = weekEntry.getValue();
String month = weekDate.substring(0, 7); // Extract the year and month
if (monthlyMap.containsKey(month)) {
// If the month entry exists, sum the values
Map&lt;String, Object&gt; existingMonthData = (Map&lt;String, Object&gt;)    monthlyMap.get(month);
sumData(existingMonthData, (Map&lt;String, Object&gt;) weekData);
} else {
// If the month entry does not exist, initialize it with the weekly data
monthlyMap.put(month, weekData);
}
}
monthlyData.put(countryId, monthlyMap);
}
return monthlyData;
}
private static void sumData(Map&lt;String, Object&gt; targetMap, Map&lt;String, Object&gt; sourceMap) {
for (Map.Entry&lt;String, Object&gt; entry : sourceMap.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (value instanceof Number) {
// If the value is numeric, sum it with the existing value
if (targetMap.containsKey(key)) {
Number existingValue = (Number) targetMap.get(key);
double sum = existingValue.doubleValue() + ((Number) value).doubleValue();
targetMap.put(key, sum);
} else {
targetMap.put(key, value);
}
}
}
}
public static void main(String[] args) {
Map&lt;String, Map&lt;String, Object&gt;&gt; weeklyData = new HashMap&lt;&gt;();
Map&lt;String, Object&gt; usWeeklyData = new HashMap&lt;&gt;();
usWeeklyData.put(&quot;2023-01-02&quot;, createWeeklyObject(1000, 500, 2000, 0.25));
usWeeklyData.put(&quot;2023-01-09&quot;, createWeeklyObject(1200, 600, 2500, 0.24));
usWeeklyData.put(&quot;2023-01-16&quot;, createWeeklyObject(1100, 550, 2300, 0.23));
usWeeklyData.put(&quot;2023-01-23&quot;, createWeeklyObject(1300, 650, 2700, 0.22));
usWeeklyData.put(&quot;2023-01-30&quot;, createWeeklyObject(1400, 700, 2900, 0.24));
usWeeklyData.put(&quot;2023-02-06&quot;, createWeeklyObject(900, 450, 1800, 0.21));
usWeeklyData.put(&quot;2023-02-13&quot;, createWeeklyObject(1000, 500, 2000, 0.25));
usWeeklyData.put(&quot;2023-02-20&quot;, createWeeklyObject(1200, 600, 2500, 0.24));
weeklyData.put(&quot;US&quot;, usWeeklyData);
Map&lt;String, Object&gt; caWeeklyData = new HashMap&lt;&gt;();
caWeeklyData.put(&quot;2023-01-02&quot;, createWeeklyObject(800, 400, 1800, 0.22));
caWeeklyData.put(&quot;2023-01-23&quot;, createWeeklyObject(950, 475, 1950, 0.23));
caWeeklyData.put(&quot;2023-01-30&quot;, createWeeklyObject(1100, 550, 2200, 0.22));
caWeeklyData.put(&quot;2023-02-06&quot;, createWeeklyObject(850, 425, 1700, 0.21));
caWeeklyData.put(&quot;2023-02-13&quot;, createWeeklyObject(900, 450, 1800, 0.22));
weeklyData.put(&quot;CA&quot;, caWeeklyData);
System.out.println(weeklyData);
// Convert to monthly data
Map&lt;String, Map&lt;String, Object&gt;&gt; monthlyData = convertToMonthlyData(weeklyData);
System.out.println(monthlyData);
}
private static Map&lt;String, Object&gt; createWeeklyObject(int productSales, int noOfUnitsSold,      int customerViews, double conversion) {
Map&lt;String, Object&gt; weeklyObject = new HashMap&lt;&gt;();
weeklyObject.put(&quot;productSales&quot;, productSales);
weeklyObject.put(&quot;noOfUnitsSold&quot;, noOfUnitsSold);
weeklyObject.put(&quot;customerViews&quot;, customerViews);
weeklyObject.put(&quot;conversion&quot;, conversion);
return weeklyObject;
}
}

I don't have much hand's on experience using lambda and streams for which I think using these concepts, this can be made even more efficiently. Can you please guide me on this one?

Thanks in advance

答案1

得分: 3

使用Java Streams,您可以参考下面的代码:

private static Map<String, Map<String, Map<String, Object>>> convertToMonthlyData(Map<String, Map<String, Object>> weeklyData) {
    DateTimeFormatter weekFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM");

    Map<String, Map<String, Map<String, Object>>> monthwiseMap = new HashMap<>();

    weeklyData.forEach((country, weeklyDataDetail) -> {
        Map<String, Map<String, Object>> countryMonthwiseMap = weeklyDataDetail.entrySet().stream()
                .collect(Collectors.groupingBy(entry -> YearMonth.parse(entry.getKey(), weekFormatter).format(monthFormatter),
                        Collectors.mapping(Map.Entry::getValue, Collectors.toList())))
                .entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, entry -> combineWeeklyData(entry.getValue())));

        monthwiseMap.put(country, countryMonthwiseMap);
    });

    return monthwiseMap;
}

private static Map<String, Object> combineWeeklyData(List<Object> weeklyData) {
    Map<String, Object> combinedData = new HashMap<>();
    int totalCustomerViews = 0;
    int totalProductSales = 0;
    int totalNoOfUnitsSold = 0;
    double totalConversion = 0.0;

    for (Object data : weeklyData) {
        if (data instanceof Map) {
            Map<String, Object> weeklyDataMap = (Map<String, Object>) data;
            totalCustomerViews += (int) weeklyDataMap.get("customerViews");
            totalProductSales += (int) weeklyDataMap.get("productSales");
            totalNoOfUnitsSold += (int) weeklyDataMap.get("noOfUnitsSold");
            totalConversion += (double) weeklyDataMap.get("conversion");
        }
    }

    int numWeeks = weeklyData.size();
    double averageConversion = (numWeeks > 0) ? totalConversion / numWeeks : 0.0;

    combinedData.put("customerViews", totalCustomerViews);
    combinedData.put("productSales", totalProductSales);
    combinedData.put("noOfUnitsSold", totalNoOfUnitsSold);
    combinedData.put("conversion", averageConversion);

    return combinedData;
}

这是您提供的Java代码的翻译部分。如果您有任何其他疑问,请随时提出。

英文:

Using Java Streams you can refer below code

private static Map&lt;String, Map&lt;String, Map&lt;String, Object&gt;&gt;&gt; convertToMonthlyData(Map&lt;String, Map&lt;String, Object&gt;&gt; weeklyData) {
DateTimeFormatter weekFormatter = DateTimeFormatter.ofPattern(&quot;yyyy-MM-dd&quot;);
DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern(&quot;yyyy-MM&quot;);
Map&lt;String, Map&lt;String, Map&lt;String, Object&gt;&gt;&gt; monthwiseMap = new HashMap&lt;&gt;();
weeklyData.forEach((country, weeklyDataDetail) -&gt; {
Map&lt;String, Map&lt;String, Object&gt;&gt; countryMonthwiseMap = weeklyDataDetail.entrySet().stream()
.collect(Collectors.groupingBy(entry -&gt; YearMonth.parse(entry.getKey(), weekFormatter).format(monthFormatter),
Collectors.mapping(Map.Entry::getValue, Collectors.toList())))
.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, entry -&gt; combineWeeklyData(entry.getValue())));
monthwiseMap.put(country, countryMonthwiseMap);
});
return monthwiseMap;
}
private static Map&lt;String, Object&gt; combineWeeklyData(List&lt;Object&gt; weeklyData) {
Map&lt;String, Object&gt; combinedData = new HashMap&lt;&gt;();
int totalCustomerViews = 0;
int totalProductSales = 0;
int totalNoOfUnitsSold = 0;
double totalConversion = 0.0;
for (Object data : weeklyData) {
if (data instanceof Map) {
Map&lt;String, Object&gt; weeklyDataMap = (Map&lt;String, Object&gt;) data;
totalCustomerViews += (int) weeklyDataMap.get(&quot;customerViews&quot;);
totalProductSales += (int) weeklyDataMap.get(&quot;productSales&quot;);
totalNoOfUnitsSold += (int) weeklyDataMap.get(&quot;noOfUnitsSold&quot;);
totalConversion += (double) weeklyDataMap.get(&quot;conversion&quot;);
}
}
int numWeeks = weeklyData.size();
double averageConversion = (numWeeks &gt; 0) ? totalConversion / numWeeks : 0.0;
combinedData.put(&quot;customerViews&quot;, totalCustomerViews);
combinedData.put(&quot;productSales&quot;, totalProductSales);
combinedData.put(&quot;noOfUnitsSold&quot;, totalNoOfUnitsSold);
combinedData.put(&quot;conversion&quot;, averageConversion);
return combinedData;
}

huangapple
  • 本文由 发表于 2023年6月29日 13:15:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76578219.html
匿名

发表评论

匿名网友

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

确定