From 77d3f1fd99cc4eb53eec1ee7080f6f4ae315e64e Mon Sep 17 00:00:00 2001 From: Nikolay Martyanov Date: Thu, 21 Dec 2023 20:44:20 +0100 Subject: [PATCH] back: Enhance Unique Path Calculation in Search Component. Refactored the formatNames function in Search.jsx to handle cases where regions with the same name appear under different parent regions or within nested structures. The updated logic includes grouping paths by the last element (region name), finding the common prefix for each group of paths, and then determining the shortest unique suffix for each region. This approach ensures that each region is uniquely identifiable, especially in scenarios where regions share the same name. Issue: #172 Signed-off-by: Nikolay Martyanov --- frontend/src/components/Search.jsx | 61 ++++++++++++++++++------------ 1 file changed, 36 insertions(+), 25 deletions(-) diff --git a/frontend/src/components/Search.jsx b/frontend/src/components/Search.jsx index 0f028df..2ec4ebd 100644 --- a/frontend/src/components/Search.jsx +++ b/frontend/src/components/Search.jsx @@ -11,38 +11,49 @@ function Search() { const { selectedRegion, setSelectedRegion, selectedHierarchyId } = useNavigation(); const prevSelectedRegion = useRef(); + // Returns an object of the form: + // { name: 'Region Name', segment: 'Region Segment (if name is not unique)', id: 'Region ID' } function formatNames(foundResults) { - const nameCount = new Map(); - foundResults.forEach((item) => { - nameCount.set(item.name, (nameCount.get(item.name) || 0) + 1); - }); - - return foundResults.map((item) => { - if (nameCount.get(item.name) === 1) { - return ({ - name: item.name, - segment: null, - id: item.id, - }); // Unique name, return as is + // Group paths by the last element (which is the same as region.name) + const pathsByLastName = {}; + foundResults.forEach((region) => { + if (!pathsByLastName[region.name]) { + pathsByLastName[region.name] = []; } - // Find the smallest unique path segment - const pathSegments = item.path.split(' > '); - let uniqueSegment = pathSegments[pathSegments.length - 1]; + pathsByLastName[region.name].push(region.path); + }); - for (let i = pathSegments.length - 2; i >= 0; i -= 1) { - const testPath = pathSegments.slice(i).join(' > '); - const isUnique = foundResults.filter((r) => r.path.includes(testPath)).length === 1; - if (isUnique) { - uniqueSegment = pathSegments.slice(i).join(' > '); + // Find the common prefix of each group of paths + function findCommonPrefixByTokens(paths) { + const tokens = paths.map((path) => path.split(' > ')); + const minLength = Math.min(...tokens.map((token) => token.length)); + let prefix = ''; + for (let i = 0; i < minLength; i += 1) { + const token = tokens[0][i]; + if (tokens.every((t) => t[i] === token)) { + prefix += `${token} > `; + } else { break; } } + return prefix; + } - return ({ - name: item.name, - segment: uniqueSegment, - id: item.id, - }); + // Process each group to find the shortest unique suffix + return foundResults.map((region) => { + const paths = pathsByLastName[region.name]; + if (paths.length === 1) { + // Only one path with this name, no need to shorten + return { name: region.name, segment: null, id: region.id }; + } + // Find the shortest unique suffix for this path + const prefix = findCommonPrefixByTokens(paths); + // Replace " >" with "," + return { + name: region.name, + segment: region.path.slice(prefix.length).replace(/ > /g, ', ').trim(','), + id: region.id, + }; }); }