基于org.json实现复杂JSON键值互换的Java方案建议
Let's break down the task: we have a JSON where roles are nested under months → regions, and we need to flip this to have roles as top-level keys, with each role mapping to regions and the list of months where that role exists in the region. No Guava BiMap allowed, so we'll use a straightforward, efficient approach with core Java collections and the org.json API.
Input JSON
{ "Roles":[ { "January":[ { "CN":[ "GoogleCnFeatureOwner", "GoogleCnAnalyst", "SupportAnalyst", "AdminCn" ] }, { "EU":[ "GoogleEuFeatureOwner", "GoogleEuAnalyst", "SupportAnalyst", "AdminEu" ] }, { "NA":[ "GoogleNaFeatureOwner", "GoogleNaAnalyst", "SupportAnalyst", "AdminNa" ] } ] }, { "February":[ { "CN":[ "AbcCnFeatureOwner", "AbcCnAnalyst", "SupportAnalyst", "AdminCn" ] }, { "EU":[ "AbcEuFeatureOwner", "AbcEuAnalyst", "SupportAnalyst", "AdminEu" ] }, { "NA":[ "AbcNaFeatureOwner", "AbcNaAnalyst", "SupportAnalyst", "AdminNa" ] } ] }, { "March":[ { "CN":[ "YahooCnFeatureOwner", "SupportAnalyst", "AdminCn", "UserCn" ] }, { "NA":[ "YahooNaFeatureOwner", "SupportAnalyst", "AdminNa", "UserNa" ] } ] } ] }
Target Output JSON
{ "GoogleCnFeatureOwner": [{ "CN": ["January"] }], "GoogleCnAnalyst": [{ "CN": ["January"] }], "SupportAnalyst": [ { "CN": ["January", "February", "March"] }, { "EU": ["January", "February"] }, { "NA": ["January", "February", "March"] } ], "AdminCn": [{ "CN": ["January", "February", "March"] }], "GoogleEuFeatureOwner": [{ "EU": ["January"] }], "GoogleEuAnalyst": [{ "EU": ["January"] }], "AdminEu": [{ "EU": ["January", "February"] }], "GoogleNaFeatureOwner": [{ "NA": ["January"] }], "GoogleNaAnalyst": [{ "NA": ["January"] }], "AdminNa": [{ "NA": ["January", "February", "March"] }], "AbcCnFeatureOwner": [{ "CN": ["February"] }], "AbcCnAnalyst": [{ "CN": ["February"] }], "AbcEuFeatureOwner": [{ "EU": ["February"] }], "AbcEuAnalyst": [{ "EU": ["February"] }], "AbcNaFeatureOwner": [{ "NA": ["February"] }], "AbcNaAnalyst": [{ "NA": ["February"] }], "YahooCnFeatureOwner": [{ "CN": ["March"] }], "UserCn": [{ "CN": ["March"] }], "YahooNaFeatureOwner": [{ "NA": ["March"] }], "UserNa": [{ "NA": ["March"] }] }
Efficient Implementation
We'll use nested HashMaps to track intermediate mappings (role → region → list of months) in a single pass over the input, then convert this structure to the final JSON. This approach ensures minimal overhead with constant-time map lookups and linear iteration.
Complete Code
import org.json.JSONArray; import org.json.JSONObject; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; public class RoleMonthAggregator { public static JSONObject aggregateRolesByMonth(JSONObject inputJson) { // Intermediate storage: Role -> Region -> List of Months Map<String, Map<String, List<String>>> roleRegionMap = new HashMap<>(); // Parse the input Roles array JSONArray rolesArray = inputJson.getJSONArray("Roles"); for (int i = 0; i < rolesArray.length(); i++) { JSONObject monthObj = rolesArray.getJSONObject(i); // Extract the month key (e.g., "January") Iterator<String> monthKeys = monthObj.keys(); if (monthKeys.hasNext()) { String month = monthKeys.next(); // Iterate over regions for the current month JSONArray regionsArray = monthObj.getJSONArray(month); for (int j = 0; j < regionsArray.length(); j++) { JSONObject regionObj = regionsArray.getJSONObject(j); // Extract the region key (e.g., "CN") Iterator<String> regionKeys = regionObj.keys(); if (regionKeys.hasNext()) { String region = regionKeys.next(); // Iterate over roles for the current region/month JSONArray rolesList = regionObj.getJSONArray(region); for (int k = 0; k < rolesList.length(); k++) { String role = rolesList.getString(k); // Safely build nested map entries without null checks roleRegionMap.computeIfAbsent(role, r -> new HashMap<>()) .computeIfAbsent(region, reg -> new ArrayList<>()) .add(month); } } } } } // Convert intermediate map to target JSON structure JSONObject resultJson = new JSONObject(); for (Map.Entry<String, Map<String, List<String>>> roleEntry : roleRegionMap.entrySet()) { String role = roleEntry.getKey(); Map<String, List<String>> regionMonthMap = roleEntry.getValue(); JSONArray regionArray = new JSONArray(); for (Map.Entry<String, List<String>> regionEntry : regionMonthMap.entrySet()) { JSONObject regionMonthObj = new JSONObject(); regionMonthObj.put(regionEntry.getKey(), new JSONArray(regionEntry.getValue())); regionArray.put(regionMonthObj); } resultJson.put(role, regionArray); } return resultJson; } public static void main(String[] args) { // Sample input JSON string String inputJsonStr = "{ \"Roles\":[{ \"January\":[{ \"CN\":[\"GoogleCnFeatureOwner\",\"GoogleCnAnalyst\",\"SupportAnalyst\",\"AdminCn\"] },{ \"EU\":[\"GoogleEuFeatureOwner\",\"GoogleEuAnalyst\",\"SupportAnalyst\",\"AdminEu\"] },{ \"NA\":[\"GoogleNaFeatureOwner\",\"GoogleNaAnalyst\",\"SupportAnalyst\",\"AdminNa\"] }] },{ \"February\":[{ \"CN\":[\"AbcCnFeatureOwner\",\"AbcCnAnalyst\",\"SupportAnalyst\",\"AdminCn\"] },{ \"EU\":[\"AbcEuFeatureOwner\",\"AbcEuAnalyst\",\"SupportAnalyst\",\"AdminEu\"] },{ \"NA\":[\"AbcNaFeatureOwner\",\"AbcNaAnalyst\",\"SupportAnalyst\",\"AdminNa\"] }] },{ \"March\":[{ \"CN\":[\"YahooCnFeatureOwner\",\"SupportAnalyst\",\"AdminCn\",\"UserCn\"] },{ \"NA\":[\"YahooNaFeatureOwner\",\"SupportAnalyst\",\"AdminNa\",\"UserNa\"] }] }] }"; JSONObject inputJson = new JSONObject(inputJsonStr); JSONObject outputJson = aggregateRolesByMonth(inputJson); // Print formatted output System.out.println(outputJson.toString(4)); } }
Key Details
Intermediate Map:
- The
roleRegionMapstores aggregated data in a hierarchy that's easy to build during parsing:- Top-level: Role name → Value: a map of regions to month lists
- This avoids duplicate entries and lets us append months to existing role-region pairs in constant time.
computeIfAbsenthandles nested map creation safely, eliminating messy null checks.
- The
Single-Pass Parsing:
- We iterate through each month, region, and role exactly once. Time complexity is O(n), where n is the total number of roles across all months/regions.
JSON Conversion:
- We convert the intermediate map to the required JSON structure by iterating through each role-region pair and building the corresponding
JSONArrayandJSONObjectentries.
- We convert the intermediate map to the required JSON structure by iterating through each role-region pair and building the corresponding
内容的提问来源于stack exchange,提问作者Mr.Green

