Skip to content

Commit 950580d

Browse files
committed
Merge branch 'feat/list-comparer' into chore/all-my-stuffs
# Conflicts: # package.json # pnpm-lock.yaml
2 parents 87512fc + 393ac40 commit 950580d

File tree

7 files changed

+254
-0
lines changed

7 files changed

+254
-0
lines changed

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"@types/lodash.flattendeep": "^4.4.9",
7070
"@types/lodash.last": "^3.0.9",
7171
"@types/turndown": "^5.0.4",
72+
"@types/arr-diff": "^4.0.3",
7273
"@types/figlet": "^1.5.8",
7374
"@types/markdown-it": "^13.0.7",
7475
"@vicons/material": "^0.12.0",
@@ -77,6 +78,7 @@
7778
"@vueuse/head": "^1.0.0",
7879
"@vueuse/router": "^10.0.0",
7980
"@zxing/library": "^0.21.0",
81+
"arr-diff": "^4.0.0",
8082
"bcryptjs": "^2.4.3",
8183
"change-case": "^4.1.2",
8284
"chatgpt-prompt-splitter": "^1.0.5",
@@ -104,6 +106,7 @@
104106
"duration-fns": "^3.0.2",
105107
"email-normalizer": "^1.0.0",
106108
"emojilib": "^3.0.10",
109+
"fast_array_intersect": "^1.1.0",
107110
"figlet": "^1.7.0",
108111
"figue": "^1.2.0",
109112
"flatten-anything": "^4.0.1",

pnpm-lock.yaml

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/tools/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ import { tool as tomlToJson } from './toml-to-json';
7474
import { tool as jsonToCsv } from './json-to-csv';
7575
import { tool as cameraRecorder } from './camera-recorder';
7676
import { tool as listConverter } from './list-converter';
77+
import { tool as listComparer } from './list-comparer';
7778
import { tool as phoneParserAndFormatter } from './phone-parser-and-formatter';
7879
import { tool as jsonDiff } from './json-diff';
7980
import { tool as ipv4RangeExpander } from './ipv4-range-expander';
@@ -176,6 +177,7 @@ export const toolsByCategory: ToolCategory[] = [
176177
jsonToYaml,
177178
jsonToToml,
178179
listConverter,
180+
listComparer,
179181
tomlToJson,
180182
tomlToYaml,
181183
htmlToMarkdown,

src/tools/list-comparer/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { List } from '@vicons/tabler';
2+
import { defineTool } from '../tool';
3+
4+
export const tool = defineTool({
5+
name: 'Lists Comparer',
6+
path: '/list-comparer',
7+
description: 'Compare two list items',
8+
keywords: ['list', 'comparer'],
9+
component: () => import('./list-comparer.vue'),
10+
icon: List,
11+
createdAt: new Date('2024-08-15'),
12+
});
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { describe, expect, it } from 'vitest';
2+
import { compareLists } from './list-comparer.service';
3+
4+
describe('list-comparer', () => {
5+
describe('compareLists', () => {
6+
it('return correct comparaison', () => {
7+
expect(compareLists({
8+
list1: '1\n 2\n3\n4\n5\n4\n7\nA',
9+
list2: '1\n2\n3\n4\n6\n4\n7\na',
10+
trimItems: true,
11+
ignoreCase: true,
12+
})).to.deep.eq({
13+
list1Not2: [
14+
'5',
15+
],
16+
list2Not1: [
17+
'6',
18+
],
19+
same: [
20+
'1',
21+
'2',
22+
'3',
23+
'4',
24+
'7',
25+
'a',
26+
],
27+
});
28+
29+
expect(compareLists({
30+
list1: '1\n 2\n3\n4\n5\n4\n7\nA',
31+
list2: '1\n2\n3\n4\n6\n4\n7\na',
32+
trimItems: false,
33+
ignoreCase: false,
34+
})).to.deep.eq({
35+
list1Not2: [
36+
' 2',
37+
'5',
38+
'A',
39+
],
40+
list2Not1: [
41+
'2',
42+
'6',
43+
'a',
44+
],
45+
same: [
46+
'1',
47+
'3',
48+
'4',
49+
'7',
50+
],
51+
});
52+
53+
expect(compareLists({
54+
list1: '1, 2,3,4,5\n4,7,A,A',
55+
list2: '1\n2\n3\n4\n6\n4\n7\na',
56+
trimItems: false,
57+
ignoreCase: false,
58+
separator: ',',
59+
})).to.deep.eq({
60+
list1Not2: [
61+
' 2',
62+
'5',
63+
'A',
64+
],
65+
list2Not1: [
66+
'2',
67+
'6',
68+
'a',
69+
],
70+
same: [
71+
'1',
72+
'3',
73+
'4',
74+
'7',
75+
],
76+
});
77+
78+
expect(compareLists({
79+
list1: '10\n20\n20\n30',
80+
list2: '30\n20\n40',
81+
trimItems: false,
82+
ignoreCase: false,
83+
})).to.deep.eq({
84+
list1Not2: [
85+
'10',
86+
],
87+
list2Not1: [
88+
'40',
89+
],
90+
same: [
91+
'30',
92+
'20',
93+
],
94+
});
95+
});
96+
});
97+
});
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import _ from 'lodash';
2+
import intersect from 'fast_array_intersect';
3+
import diff from 'arr-diff';
4+
5+
export function compareLists({
6+
list1,
7+
list2,
8+
ignoreCase = false,
9+
trimItems = true,
10+
separator = '',
11+
}: {
12+
list1: string
13+
list2: string
14+
separator?: string
15+
ignoreCase?: boolean
16+
trimItems?: boolean
17+
}) {
18+
const splitSep = separator ? `${separator}|` : '';
19+
const splitRegExp = new RegExp(`(?:${splitSep}\\n)`, 'g');
20+
21+
const prepareList = (list: string) =>
22+
_.chain(list ?? '')
23+
.thru(text => ignoreCase ? text.toLowerCase() : text)
24+
.split(splitRegExp)
25+
.map(text => trimItems ? text.trim() : text)
26+
.value();
27+
28+
const list1Arr = prepareList(list1);
29+
const list2Arr = prepareList(list2);
30+
31+
return {
32+
same: [...new Set(intersect([list1Arr, list2Arr]))],
33+
list2Not1: [...new Set(diff(list2Arr, list1Arr))],
34+
list1Not2: [...new Set(diff(list1Arr, list2Arr))],
35+
};
36+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<script setup lang="ts">
2+
import { compareLists } from './list-comparer.service';
3+
4+
const compareConfig = useStorage<{ ignoreCase: boolean; trimItems: boolean; noDuplicate: boolean; separator: string }>('list-cmp:conf', {
5+
ignoreCase: false,
6+
trimItems: true,
7+
noDuplicate: false,
8+
separator: '',
9+
});
10+
const list1 = ref('');
11+
const list2 = ref('');
12+
13+
const compareResult = computed(() => {
14+
return compareLists({
15+
list1: list1.value,
16+
list2: list2.value,
17+
ignoreCase: compareConfig.value.ignoreCase,
18+
trimItems: compareConfig.value.trimItems,
19+
separator: compareConfig.value.separator,
20+
});
21+
});
22+
</script>
23+
24+
<template>
25+
<div>
26+
<n-space justify="center" gap-1 align="baseline">
27+
<n-form-item
28+
label="Trim items"
29+
label-placement="left"
30+
>
31+
<n-switch v-model:value="compareConfig.trimItems" />
32+
</n-form-item>
33+
34+
<n-form-item
35+
label="Ignore case"
36+
label-placement="left"
37+
mb-2
38+
>
39+
<n-switch v-model:value="compareConfig.ignoreCase" />
40+
</n-form-item>
41+
42+
<n-form-item
43+
label="Separator"
44+
label-placement="left"
45+
>
46+
<n-input
47+
v-model:value="compareConfig.separator"
48+
placeholder="Additional separator"
49+
/>
50+
</n-form-item>
51+
</n-space>
52+
53+
<div flex gap-1>
54+
<c-input-text
55+
v-model:value="list1"
56+
multiline
57+
rows="10"
58+
label="List 1"
59+
/>
60+
<c-input-text
61+
v-model:value="list2"
62+
multiline
63+
rows="10"
64+
label="List 2"
65+
/>
66+
</div>
67+
68+
<div v-if="list1 || list2">
69+
<n-divider />
70+
71+
<c-card title="Items in both lists" mb-2>
72+
<textarea-copyable :value="compareResult.same.join('\n')" />
73+
</c-card>
74+
<c-card title="Items in List 1 but not in List 2" mb-2>
75+
<textarea-copyable :value="compareResult.list1Not2.join('\n')" />
76+
</c-card>
77+
<c-card title="Items in List 2 but not in List 1" mb-2>
78+
<textarea-copyable :value="compareResult.list2Not1.join('\n')" />
79+
</c-card>
80+
</div>
81+
</div>
82+
</template>

0 commit comments

Comments
 (0)