在产品管理系统的开发过程中,我们常常需要为不同产品配置对应的frontName值,用于前端展示或接口返回。当产品名称存在重复和唯一两种情况时,如何高效地为它们设置不同的frontName值,是很多开发者会遇到的问题。

需求场景说明
假设我们有一个产品列表,其中部分产品名称重复,部分产品名称唯一。业务要求如下:
- 名称唯一的产品,直接使用产品名称作为frontName值
- 名称重复的产品,需要在frontName后添加序号,比如
产品A_1、产品A_2
基础实现逻辑
核心思路是先统计所有产品名称的出现次数,再遍历产品列表,根据名称的出现次数判断是否需要添加序号。以下是JavaScript的实现示例:
// 产品原始数据
const productList = [
{ id: 1, name: '无线耳机' },
{ id: 2, name: '无线耳机' },
{ id: 3, name: '机械键盘' },
{ id: 4, name: '无线鼠标' },
{ id: 5, name: '机械键盘' }
];
// 第一步:统计每个产品名称的出现次数
const nameCountMap = {};
productList.forEach(item => {
const name = item.name;
if (nameCountMap[name]) {
nameCountMap[name] += 1;
} else {
nameCountMap[name] = 1;
}
});
// 第二步:记录重复名称的当前序号
const repeatNameIndexMap = {};
// 第三步:为产品设置frontName
const resultList = productList.map(item => {
const name = item.name;
// 如果名称只出现一次,直接作为frontName
if (nameCountMap[name] === 1) {
return { ...item, frontName: name };
}
// 如果名称重复,添加序号
if (!repeatNameIndexMap[name]) {
repeatNameIndexMap[name] = 1;
}
const frontName = `${name}_${repeatNameIndexMap[name]}`;
repeatNameIndexMap[name] += 1;
return { ...item, frontName: frontName };
});
console.log(resultList);
优化方案:规则配置化
如果后续业务规则变化,比如重复名称的frontName需要添加后缀而不是下划线加序号,或者唯一名称需要添加固定前缀,我们可以把规则抽离成配置,提升代码的可维护性。
// 规则配置
const frontNameConfig = {
// 唯一名称的处理函数
uniqueNameHandler: (name) => name,
// 重复名称的处理函数
repeatNameHandler: (name, index) => `${name}_${index}`
};
// 通用处理逻辑
function setFrontNameForProducts(products, config) {
const nameCountMap = {};
products.forEach(item => {
const name = item.name;
nameCountMap[name] = (nameCountMap[name] || 0) + 1;
});
const repeatNameIndexMap = {};
return products.map(item => {
const name = item.name;
if (nameCountMap[name] === 1) {
return { ...item, frontName: config.uniqueNameHandler(name) };
}
if (!repeatNameIndexMap[name]) {
repeatNameIndexMap[name] = 1;
}
const index = repeatNameIndexMap[name];
repeatNameIndexMap[name] += 1;
return { ...item, frontName: config.repeatNameHandler(name, index) };
});
}
// 使用配置调用
const processedList = setFrontNameForProducts(productList, frontNameConfig);
console.log(processedList);
后端实现参考(Java示例)
如果是后端需要处理这个逻辑,以下是Java的实现示例:
import java.util.*;
class Product {
private Integer id;
private String name;
private String frontName;
// 构造方法、getter、setter省略
}
public class FrontNameUtil {
public static List<Product> setFrontName(List<Product> productList) {
// 统计名称出现次数
Map<String, Integer> nameCountMap = new HashMap<>();
for (Product product : productList) {
String name = product.getName();
nameCountMap.put(name, nameCountMap.getOrDefault(name, 0) + 1);
}
// 记录重复名称的序号
Map<String, Integer> repeatNameIndexMap = new HashMap<>();
List<Product> resultList = new ArrayList<>();
for (Product product : productList) {
String name = product.getName();
Product newProduct = new Product();
newProduct.setId(product.getId());
newProduct.setName(name);
if (nameCountMap.get(name) == 1) {
// 唯一名称
newProduct.setFrontName(name);
} else {
// 重复名称
int index = repeatNameIndexMap.getOrDefault(name, 1);
newProduct.setFrontName(name + "_" + index);
repeatNameIndexMap.put(name, index + 1);
}
resultList.add(newProduct);
}
return resultList;
}
}
注意事项
- 如果产品名称包含特殊字符,需要先做清洗再统计次数,避免因为特殊字符导致判断错误
- 如果产品数量非常大,统计名称次数的步骤可以优化为流式处理,避免占用过多内存
- 序号的起始值可以根据业务需求调整,比如从0开始或者从1开始
- 如果后续需要支持更多分类规则,可以在配置中扩展不同的处理函数,不需要修改核心逻辑