外包偷吃了正编的下午茶,被公司定为恶性事件~
刚刷到个贴子,说深圳某公司发通告:外包人员偷吃了正编的下午茶,被定性为“恶性事件”,后续还要赔偿+隔离就餐区。😅
作为程序员,我看这事有点无语。下午茶这点零食,说大不大,但被公司上升到“恶性事件”,其实折射的不是吃没吃的问题,而是身份和信任感的矛盾。在很多公司,外包本来就被边缘化,工位、权限、福利都分层,这一口茶歇成了压垮关系的稻草。
网友有人笑说“何必小题大做”,也有人觉得“制度面前人人平等”。但换我说,程序员日常都讲权限管理,你把资源边界划清楚,别人自然不会踩雷。反过来说,如果制度模糊、心态又排斥,那迟早出问题。
归根结底,茶歇不是重点,尊重和规则才是核心。只要界限透明,沟通清楚,就算是外包,也能像团队的一份子。总的来说,制度是死的,人心是活的,别让小事撕裂了合作氛围。【备注:文末可领最新资料】
算法题:完全相等的 JSON 字符串
昨天晚上十一点多,在公司楼下吹风儿,手机那边小李又问:“哥,两个 JSON 字符串到底怎么判完全相等啊?为啥我 trim 了还不行?”我一口热奶茶差点洒了——这个事儿,别靠肉眼瞪,得按“结构”和“类型”来比,对吧。
就是那个…怎么说呢…不是看字符一模一样,而是解析后的值一样:
类型要对上:对象对对象,数组对数组,数字别和字符串混。 对象里键顺序不算事儿,但键集合和对应值要一一匹配。 数组必须同长度、同位置相等,这个顺序不能乱。 数字这块最坑: 1和1.0人看像,机器常当不一样。我一般把它们都拉到BigDecimal比一下精度。
思路就三步
第一步,把俩字符串解析成树;第二步,按类型递归比较;第三步,数字用 BigDecimal,对象按键集合遍历,数组按下标走。这样空格、换行、键顺序这些“表面功夫”就都忽略了。哦对,null 也是值,不能和 "null" 搞混。
有人问我那个配置怎么写…咳我先说坑:
布尔和字符串 "true"不一样;科学计数法 1e2和100需要转成BigDecimal再比;不合法的 JSON 别逞强,直接抛错或者返回不相等; Unicode 转义 "\u0041"和"A",大多数解析器会还原,解析后自然能对上。
我现在困得眼睛直眨,但代码给你们放这儿,就这个思路,落地很稳。
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.*;
import java.math.BigDecimal;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
publicclassJsonDeepEqual{
privatestaticfinal ObjectMapper MAPPER = new ObjectMapper();
publicstaticbooleanjsonEqual(String a, String b){
try {
JsonNode n1 = MAPPER.readTree(a);
JsonNode n2 = MAPPER.readTree(b);
return deepEqual(n1, n2);
} catch (JsonProcessingException e) {
// 非法 JSON,按需处理:这里直接认为不相等
returnfalse;
}
}
privatestaticbooleandeepEqual(JsonNode a, JsonNode b){
if (a == null || b == null) return a == b;
if (a.getNodeType() != b.getNodeType()) {
// 特判数字:不同数值节点类型也可能等
if (isNumber(a) && isNumber(b)) {
return numberEqual(a, b);
}
returnfalse;
}
switch (a.getNodeType()) {
case NULL: returntrue;
case BOOLEAN: return a.booleanValue() == b.booleanValue();
case NUMBER: return numberEqual(a, b);
case STRING: return a.textValue().equals(b.textValue());
case ARRAY:
if (a.size() != b.size()) returnfalse;
for (int i = 0; i < a.size(); i++) {
if (!deepEqual(a.get(i), b.get(i))) returnfalse;
}
returntrue;
case OBJECT:
// 键顺序忽略:用排序后的视图比较
if (a.size() != b.size()) returnfalse;
Map<String, JsonNode> ma = new TreeMap<>();
Map<String, JsonNode> mb = new TreeMap<>();
Iterator<Map.Entry<String, JsonNode>> ia = a.fields();
Iterator<Map.Entry<String, JsonNode>> ib = b.fields();
while (ia.hasNext()) {
Map.Entry<String, JsonNode> e = ia.next();
ma.put(e.getKey(), e.getValue());
}
while (ib.hasNext()) {
Map.Entry<String, JsonNode> e = ib.next();
mb.put(e.getKey(), e.getValue());
}
if (!ma.keySet().equals(mb.keySet())) returnfalse;
for (String k : ma.keySet()) {
if (!deepEqual(ma.get(k), mb.get(k))) returnfalse;
}
returntrue;
default:
return a.equals(b); // 保险兜底
}
}
privatestaticbooleanisNumber(JsonNode n){
return n != null && n.isNumber();
}
privatestaticbooleannumberEqual(JsonNode a, JsonNode b){
BigDecimal x = new BigDecimal(a.asText());
BigDecimal y = new BigDecimal(b.asText());
return x.compareTo(y) == 0;
}
// 小测一下
publicstaticvoidmain(String[] args){
String s1 = "{\"a\":1,\"b\":[true, null, {\"x\":\"A\"}]}";
String s2 = "{ \"b\" : [ true , null , {\"x\":\"\\u0041\"} ], \"a\" : 1.0 }";
System.out.println(jsonEqual(s1, s2)); // true
}
}
对了,如果你们遇到 NaN、Infinity 那些,标准 JSON 本来就不该有,直接当非法处理就省心了。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html