សំណុំ និងប្រតិបត្តិការសំណុំ

មាតិកា

  1. តើសំណុំ (Set) ជាអ្វី?
  2. Set ទល់នឹង Array
  3. Set របស់ JavaScript
  4. គិតតាមដ្យាក្រាម Venn
  5. Union, Intersection, Difference
  6. Subset និង Symmetric Difference
  7. សំណួរពិត Set ពិត
  8. Set, Bit Flag និង SQL
  9. រូបមន្ត៖ sets.js សម្រាប់ mathlab
  10. សាកល្បងដោយខ្លួនឯង

1. តើសំណុំ (Set) ជាអ្វី?

Set គឺជាបណ្តុំនៃវត្ថុដែលខុសៗគ្នា ដែលមានតែសំណួរពីរប៉ុណ្ណោះសំខាន់៖

  • តើវត្ថុនេះ នៅក្នុង set ឬអត់?
  • តើមានវត្ថុប៉ុន្មាននៅក្នុងវា?

ប៉ុណ្ណឹងហើយ។ Set មិនមានធាតុទីមួយ មិនមានធាតុទីពីរ និងមិនមានធាតុស្ទួនទេ។ Set នៃ tag លើប្រកាសប្លុក {css, js, html} គឺជា set ដូចគ្នានឹង {html, css, js}។ ការសរសេរ js ពីរដងមិនធ្វើឲ្យវាជាសមាជិកច្រើនជាងមុនទេ។

វិទ្យាសាស្ត្រកុំព្យូទ័រស្រឡាញ់ set ព្រោះសំណួរពិតជាច្រើនពិតជាសំណួរអំពីក្រុម៖

  • តើអ្នកប្រើណាខ្លះមាន role admin?
  • តើផលិតផលណាខ្លះនៅក្នុងរទេះរបស់ខ្ញុំ ហើយ កំពុងបញ្ចុះតម្លៃ?
  • តើសិស្សណាខ្លះបានចូលរៀនថ្នាក់ ប៉ុន្តែមិនដែលដាក់កិច្ចការផ្ទះ?
  • តើអ្នកប្រើនេះមានសិទ្ធិអ្វីខ្លះ?

ប្រសិនបើអ្នកអាចបង្ហាញបញ្ហារបស់អ្នកជា "ក្រុមនៃវត្ថុ" និង "តើក្រុមទាំងនោះត្រួតគ្នាយ៉ាងដូចម្តេច" នោះ set នឹងធ្វើឲ្យកូដខ្លីជាង និងការគិតច្បាស់ជាង។

2. Set ទល់នឹង Array

អ្នកស្គាល់ array រួចហើយ។ ចុះ set ខុសគ្នាយ៉ាងណា?

ArraySet
លំដាប់សំខាន់បាទ/ចាសទេ (JavaScript ចងចាំលំដាប់នៃការបញ្ចូល ប៉ុន្តែគំនិតនេះមិនប្រើវាទេ)
អនុញ្ញាតឲ្យមានធាតុស្ទួនបាទ/ចាសទេ
រកតាមទីតាំង (list[2])បាទ/ចាសទេ
"តើ X នៅក្នុងនេះទេ?"យឺតសម្រាប់បញ្ជីធំ (មើលធាតុម្តងមួយៗ)លឿន (លោតត្រង់ទៅចម្លើយ)

ប្រើ array នៅពេល លំដាប់ ឬ ទីតាំង សំខាន់៖ playlist ជំហាននៃរូបមន្តធ្វើម្ហូប បញ្ជីលទ្ធផលស្វែងរកដែលតម្រៀបតាមពិន្ទុ។ ប្រើ set នៅពេលអ្នកខ្វល់តែ សមាជិកភាព៖ បញ្ជី tag ID របស់អ្នកប្រើដែលបានបោះឆ្នោតរួច ពាក្យដែលបានឃើញរហូតមកដល់ពេលនេះ។

ជួរ "លឿន" មានសារៈសំខាន់។ ក្នុង ជំពូកទី 9 អ្នកនឹងវាស់ថាលឿនជាងប៉ុន្មានយ៉ាងពិតប្រាកដ ប៉ុន្តែនេះគឺជាគំនិត។ ជាមួយ array នៃ ID មួយលាន includes ប្រហែលជាត្រូវមើលគ្រប់ធាតុ។ Set អាចឆ្លើយ "តើ ID នេះនៅទីនេះទេ?" ស្ទើរតែភ្លាមៗ មិនថាវាធំប៉ុនណាក៏ដោយ ដោយសារល្បិចមួយហៅថា hashing (អ្នកនឹងឃើញញាតិរបស់វានៅ ជំពូកទី 6)។

3. Set របស់ JavaScript

JavaScript មាន Set ជាប់មកជាមួយ។ មូលដ្ឋាន៖

const tags = new Set();

tags.add("css");
tags.add("js");
tags.add("css"); // មានរួចហើយ៖ គ្មានអ្វីកើតឡើងទេ

console.log(tags.size);      // 2
console.log(tags.has("js")); // true
console.log(tags.has("go")); // false

tags.delete("js");
console.log([...tags]);      // [ 'css' ]

new Set() បង្កើត set ទទេ។ .add() ដាក់តម្លៃចូល។ .has() សួរសំណួរសមាជិកភាព។ .delete() លុបចេញ។ .size គឺជា property (គ្មានវង់ក្រចក) មិនដូច .length របស់ array ទេ ប៉ុន្តែវាដំណើរការដូចគ្នា។ Spread syntax [...tags] បំប្លែង set ត្រឡប់ទៅជា array វិញ។

ល្បិចដ៏ពេញនិយមបំផុតគឺ ការលុបធាតុស្ទួន ចេញពី array៖ បង្កើត set ពី array រួច spread វាត្រឡប់មកវិញ៖

const tags = ["css", "js", "css", "html", "js"];
const unique = [...new Set(tags)];

console.log(unique); // [ 'css', 'js', 'html' ]

Set ប្រៀបធៀបតម្លៃតាមច្បាប់ដូច === ជាមួយករណីលើកលែងដ៏មានមេត្តាមួយ៖ NaN រាប់ថាស្មើនឹងខ្លួនឯង។ នោះមានអន្ទាក់សម្រាប់ object និង array ដែលត្រូវបានប្រៀបធៀបតាម identity មិនមែនតាមមាតិកាទេ៖

console.log(new Set([1, "1"]).size);       // 2   (type ខុសគ្នា)
console.log(new Set([[1], [1]]).size);     // 2   (array ពីរខុសគ្នា)

ដូច្នេះ set នៃ object មិនមែនជា set នៃ "record ដែលមាន field ដូចគ្នា" ទេ។ ប្រសិនបើធាតុរបស់អ្នកជា object សូមរក្សាទុកសោតែមួយគត់ដូចជា user.id ក្នុង set ជំនួសវិញ។

4. គិតតាមដ្យាក្រាម Venn

ដ្យាក្រាម Venn គូរ set នីមួយៗជារង្វង់។ កន្លែងដែលរង្វង់ត្រួតគ្នាគឺជាធាតុដែលជាកម្មសិទ្ធិរបស់ទាំងពីរ។ អ្នកប្រហែលជាធ្លាប់ឃើញមួយនៅសាលា។ វានៅតែជាឧបករណ៍ល្អបំផុតសម្រាប់បញ្ហា set ដូច្នេះសូមគូរមួយលើក្រដាសរាល់ពេលដែលសំណួរមានពាក្យ "និង" "ឬ" "ប៉ុន្តែមិនមែន" ឬ "តែប៉ុណ្ណោះ"។

យក set មនុស្សពីរ៖

Signed up: Dara, Sokha, Vanna, Bopha
Paid:      Sokha, Bopha, Chantha

គូររង្វង់ពីរដែលត្រួតគ្នា។ Sokha និង Bopha ទៅក្នុងផ្នែកត្រួតគ្នា ព្រោះពួកគេនៅក្នុងទាំងពីរ។ Dara និង Vanna ទៅក្នុងរង្វង់ "signed up" តែប៉ុណ្ណោះ។ Chantha ទៅក្នុងរង្វង់ "paid" តែប៉ុណ្ណោះ (ប្រហែលជាភ្ញៀវដែលមកផ្ទាល់ ហើយបង់ប្រាក់នៅមាត់ទ្វារ)។

រាល់សំណួរដែលអ្នកអាចសួរ គឺជាវិធីដើម្បីបិទពណ៌ផ្នែកមួយនៃរូបភាពនោះ។ ផ្នែកបន្ទាប់ផ្តល់ឈ្មោះដល់ការបិទពណ៌នីមួយៗ។

5. Union, Intersection, Difference

សន្មតថា A ជា set ដែលបានចុះឈ្មោះ និង B ជា set ដែលបានបង់ប្រាក់។ ប្រតិបត្តិការស្នូលទាំងបីគឺ៖

ប្រតិបត្តិការនិមិត្តសញ្ញាពាក្យធម្មតាលទ្ធផលសម្រាប់ឧទាហរណ៍របស់យើង
UnionA ∪ Bនៅក្នុង A ឬនៅក្នុង B ឬទាំងពីរDara, Sokha, Vanna, Bopha, Chantha
IntersectionA ∩ Bនៅក្នុង A ហើយ នៅក្នុង BSokha, Bopha
DifferenceA \ Bនៅក្នុង A ប៉ុន្តែមិននៅក្នុង BDara, Vanna

សូមកត់សម្គាល់ថាវាមានអារម្មណ៍ស្រដៀងនឹងជំពូកមុនប៉ុនណា។ Union គឺ OR, intersection គឺ AND ហើយ difference គឺ "A AND NOT B"។ Boolean logic អនុវត្តលើក្រុម។

Difference មិនស៊ីមេទ្រីទេ។ A \ B (បានចុះឈ្មោះ ប៉ុន្តែមិនបានបង់ប្រាក់) គឺជាក្រុមខុសពី B \ A (បានបង់ប្រាក់ ប៉ុន្តែមិនដែលបានចុះឈ្មោះ)៖ Dara និង Vanna ទល់នឹង Chantha។

Set របស់ JavaScript មិនផ្តល់ទាំងនេះជា method នៅលើ runtime ចាស់ៗទេ ប៉ុន្តែពួកវាត្រូវការតែមួយបន្ទាត់ម្នាក់។ ដោយប្រើ spread operator និង filter៖

const signedUp = new Set(["Dara", "Sokha", "Vanna", "Bopha"]);
const paid = new Set(["Sokha", "Bopha", "Chantha"]);

const union = new Set([...signedUp, ...paid]);
const both = new Set([...signedUp].filter((name) => paid.has(name)));
const unpaid = new Set([...signedUp].filter((name) => !paid.has(name)));

console.log(union); // Set(5) { 'Dara', 'Sokha', 'Vanna', 'Bopha', 'Chantha' }
console.log(both);  // Set(2) { 'Sokha', 'Bopha' }
console.log(unpaid); // Set(2) { 'Dara', 'Vanna' }

សូមអានបន្ទាត់ unpaid ឮៗ៖ "យកអ្នកទាំងអស់ដែលបានចុះឈ្មោះ រក្សាទុកអ្នកដែល paid មិនមាន"។ វាជាប្រយោគត្រឹមត្រូវដែលអ្នកនឹងនិយាយទៅកាន់មិត្តរួមការងារ។

ក៏មានច្បាប់រាប់ដ៏មានប្រយោជន៍មួយដែរ។ ទំហំនៃ union ស្មើនឹងទំហំនៃ set ទាំងពីរបូកគ្នា ដកផ្នែកត្រួតគ្នា ព្រោះផ្នែកត្រួតគ្នាត្រូវបានរាប់ពីរដង៖

console.log(union.size);                           // 5
console.log(signedUp.size + paid.size - both.size); // 5  (4 + 3 - 2)

JavaScript ថ្មី៖ runtime ថ្មីៗ (Node 22 និង browser បច្ចុប្បន្ន) មាន method union(), intersection(), difference(), symmetricDifference() និង isSubsetOf() ជាប់មកជាមួយលើ Set។ យើងសរសេរដោយខ្លួនឯងក្នុងស៊េរីនេះ ដើម្បីឲ្យវាដំណើរការគ្រប់ទីកន្លែង ហើយដើម្បីឲ្យអ្នកឃើញថាពួកវាធ្វើអ្វីនៅខាងក្នុង។

6. Subset និង Symmetric Difference

គំនិតពីរទៀតបំពេញប្រអប់ឧបករណ៍។

Set A គឺជា subset នៃ B (A ⊆ B) នៅពេល គ្រប់ ធាតុនៃ A ក៏នៅក្នុង B ដែរ។ វាឆ្លើយ "តើ B គ្របដណ្តប់អ្វីៗទាំងអស់ដែល A ត្រូវការឬទេ?" ឧទាហរណ៍ អ្នកប្រើមួយមានសិទ្ធិ {read, write}។ សកម្មភាពមួយត្រូវការ {read}។ តើ set ដែលត្រូវការជា subset នៃអ្វីដែលអ្នកប្រើមានឬទេ? បាទ/ចាស ដូច្នេះសកម្មភាពនោះត្រូវបានអនុញ្ញាត។ សកម្មភាពផ្សេងមួយត្រូវការ {read, delete}។ នោះមិនមែនជា subset ទេ ព្រោះ delete បាត់។

function isSubset(a, b) {
  return [...a].every((item) => b.has(item));
}

const has = new Set(["read", "write"]);

console.log(isSubset(new Set(["read"]), has));           // true
console.log(isSubset(new Set(["read", "delete"]), has)); // false
console.log(isSubset(new Set(), has));                   // true

បន្ទាត់ចុងក្រោយធ្វើឲ្យមនុស្សភ្ញាក់ផ្អើល៖ set ទទេ គឺជា subset នៃគ្រប់ set។ គិតថាវាជា "សកម្មភាពដែលមិនត្រូវការសិទ្ធិអ្វី តែងតែត្រូវបានអនុញ្ញាត"។ នេះគឺជាតក្កវិជ្ជាដូចគ្នាដែល [].every(...) តែងតែត្រឡប់ true ដែលអ្នកបានឃើញក្នុង array method។

Symmetric difference គឺ "នៅក្នុង set មួយ ឬមួយទៀត ប៉ុន្តែមិននៅក្នុងទាំងពីរ"។ វាជាកំណែ set នៃ XOR ពី Boolean Logic។ ដើម្បីរកអ្វីដែលបានប្តូររវាងបញ្ជីម្សិលមិញ និងបញ្ជីថ្ងៃនេះ វាផ្តល់ឲ្យអ្នកនូវអ្នកទាំងអស់ដែលបានចូលរួម ឬ ចាកចេញ។ អ្នកអាចបង្កើតវាពីបំណែកដែលអ្នកមានរួចហើយ៖ (A \ B) ∪ (B \ A)។

// signedUp និង paid ពីផ្នែកមុន
const odd = new Set([
  ...[...signedUp].filter((x) => !paid.has(x)),
  ...[...paid].filter((x) => !signedUp.has(x)),
]);

console.log(odd); // Set(3) { 'Dara', 'Vanna', 'Chantha' }

Set ពីរ ស្មើគ្នា នៅពេលដែលនីមួយៗជា subset នៃមួយទៀត។ លំដាប់មិនសំខាន់ទេ។

7. សំណួរពិត Set ពិត

នេះគឺជារបៀបដែលសំណួរផលិតផលទូទៅប្រែទៅជាប្រតិបត្តិការ set៖

សំណួរប្រតិបត្តិការ set
អ្នកប្រើដែលបានទិញ ហើយ បានវាយតម្លៃintersection
អ្នកប្រើដែលបានទិញ ឬ បានវាយតម្លៃunion
អ្នកប្រើដែលបានទិញ ប៉ុន្តែមិនដែលវាយតម្លៃdifference
Tag ដែលប្រកាសនេះមាន ប៉ុន្តែសេចក្តីព្រាងខ្វះdifference
តើអ្នកប្រើបានផ្តល់គ្រប់សិទ្ធិដែលទំព័រនេះតម្រូវឬទេ?subset
តើអ្វីបានប្តូររវាង snapshot ពីរនៃបញ្ជី?symmetric difference
លុប ID ស្ទួនnew Set(array)

ឧទាហរណ៍តូចមួយ។ ក្រុមទីផ្សារចង់ផ្ញើអ៊ីមែលទៅអ្នកទាំងអស់ដែលបានបើកព្រឹត្តិបត្រ ប៉ុន្តែ មិនទាន់ បានទិញសំបុត្រ៖

const opened = new Set([101, 102, 103, 104, 105]);
const bought = new Set([102, 105, 200]);

const toEmail = [...opened].filter((id) => !bought.has(id));

console.log(toEmail); // [ 101, 103, 104 ]

សូមកត់សម្គាល់លំនាំ៖ loop លើ set ដែល តូចជាង ឬពាក់ព័ន្ធជាង ហើយសាកល្បងសមាជិកភាពក្នុង set មួយទៀតដោយ .has()។ ដោយសារ .has() លឿន វាអាចពង្រីកទៅដល់ ID រាប់លាន។ ការងារដូចគ្នាដែលធ្វើដោយ opened.filter((id) => !boughtArray.includes(id)) នឹងយឺតជាងឆ្ងាយ នៅពេល boughtArray ធំណាស់។

Set ប្រចាំថ្ងៃមួយទៀត៖ ការលុបធាតុស្ទួន ខណៈរក្សាលំដាប់ដែលឃើញដំបូង ព្រោះ Set ចងចាំលំដាប់ដែលធាតុត្រូវបានបន្ថែម៖

const visits = ["/", "/blog", "/", "/cohort", "/blog"];

console.log([...new Set(visits)]); // [ '/', '/blog', '/cohort' ]

8. Set, Bit Flag និង SQL

ទំនាក់ទំនងពីរនឹងធ្វើឲ្យជំពូកក្រោយៗងាយស្រួលជាងមុន។

Bit flag គឺជា set។ នៅ ជំពូកទី 3 លេខតែមួយបានរក្សាទុកសិទ្ធិ READ = 1, WRITE = 2, EXEC = 4។ លេខនោះ គឺជា set ដែលខ្ចប់ក្នុង bit ហើយ bitwise operator គឺជាប្រតិបត្តិការ set៖

ប្រតិបត្តិការ setកំណែ bitwise
Union A ∪ Ba | b
Intersection A ∩ Ba & b
Difference A \ Ba & ~b
Symmetric differencea ^ b
const READ = 1, WRITE = 2, EXEC = 4;

const a = READ | WRITE; // 3: {read, write}
const b = WRITE | EXEC; // 6: {write, exec}

console.log(a | b);  // 7  (read, write, exec)
console.log(a & b);  // 2  (write only)
console.log(a & ~b); // 1  (read only)
console.log(a ^ b);  // 5  (read and exec)

កំណែ bitmask តូចហើយលឿនខ្លាំង ប៉ុន្តែវាដំណើរការតែនៅពេលធាតុដែលអាចមានគឺជាបញ្ជីតូចថេរ (រហូតដល់ 31 flag ក្នុងចំនួនគត់ JavaScript ធម្មតា)។ Set ដំណើរការសម្រាប់តម្លៃណាក៏បាន ដូចជាឈ្មោះ ឬ ID។ ជ្រើសឧបករណ៍ដែលត្រូវនឹងបញ្ហា។

SQL join ក៏ជាប្រតិបត្តិការ set ដែរ។ ប្រសិនបើអ្នកធ្លាប់ប្រើ database INNER JOIN រក្សាជួរដែលត្រូវគ្នាទាំងសងខាង ដែលជា intersection។ LEFT JOIN ... WHERE right.id IS NULL រក្សាជួរពីខាងឆ្វេងដែលគ្មានដៃគូនៅខាងស្តាំ ដែលជា difference។ UNION ក្នុង SQL គឺ union តាមន័យត្រង់។ ការគិតជាដ្យាក្រាម Venn ជួយអ្នកជ្រើស join ត្រឹមត្រូវមុនពេលអ្នកសរសេរវា។

9. រូបមន្ត៖ sets.js សម្រាប់ mathlab

បន្ថែម set helper ទៅក្នុង mathlab។ បង្កើត src/sets.js៖

// រាល់ function ទទួល Set ពីរ ហើយត្រឡប់ Set ថ្មី។
export function union(a, b) {
  return new Set([...a, ...b]);
}

export function intersection(a, b) {
  return new Set([...a].filter((x) => b.has(x)));
}

export function difference(a, b) {
  return new Set([...a].filter((x) => !b.has(x)));
}

export function symmetricDifference(a, b) {
  return union(difference(a, b), difference(b, a));
}

export function isSubset(a, b) {
  return [...a].every((x) => b.has(x));
}

គ្មានមួយណាក្នុងចំណោមទាំងនេះប្តូរ input របស់វាទេ។ ពួកវាបង្កើត និងត្រឡប់ set ថ្មី ដែលធ្វើឲ្យវាមានសុវត្ថិភាពក្នុងការហៅពីគ្រប់ទីកន្លែង។ symmetricDifference ប្រើ function ពីរខាងលើវាឡើងវិញ ដូច្នេះវាមិនត្រូវការតក្កវិជ្ជាថ្មីទេ។

បន្ថែមវាទៅ src/index.js៖

export * from "./sets.js";

ឥឡូវសាកល្បងក្នុង demo.js៖

import {
  union,
  intersection,
  difference,
  symmetricDifference,
  isSubset,
} from "./src/sets.js";

const signedUp = new Set(["Dara", "Sokha", "Vanna", "Bopha"]);
const paid = new Set(["Sokha", "Bopha", "Chantha"]);

console.log(union(signedUp, paid));
console.log(intersection(signedUp, paid));
console.log(difference(signedUp, paid));
console.log(symmetricDifference(signedUp, paid));
console.log(isSubset(new Set(["Sokha"]), signedUp));
console.log(isSubset(paid, signedUp));

ដំណើរការវា៖

node demo.js
Set(5) { 'Dara', 'Sokha', 'Vanna', 'Bopha', 'Chantha' }
Set(2) { 'Sokha', 'Bopha' }
Set(2) { 'Dara', 'Vanna' }
Set(3) { 'Dara', 'Vanna', 'Chantha' }
true
false

បន្ទាត់ចុងក្រោយគឺ false ព្រោះ Chantha បានបង់ប្រាក់ដោយមិនបានចុះឈ្មោះ ដូច្នេះ paid មិនត្រូវបានគ្របដណ្តប់ដោយ signedUp ទេ។

10. សាកល្បងដោយខ្លួនឯង

  1. លុបធាតុស្ទួន។ សរសេរ unique(array) ដែលត្រឡប់ array គ្មានធាតុស្ទួន តាមលំដាប់ដែលឃើញដំបូង។ សាកល្បងជាមួយ [3, 1, 3, 2, 1]។
  2. សំណួរ set ពីរ។ ដោយប្រើ courseA = {"Dara", "Sokha", "Vanna"} និង courseB = {"Vanna", "Bopha"} រកអ្នកណារៀនទាំងពីរវគ្គ អ្នកណារៀនយ៉ាងហោចណាស់មួយ និងអ្នកណារៀនតែវគ្គ A។
  3. Set ស្មើគ្នា។ សរសេរ isEqual(a, b) ដោយប្រើ isSubset ពីរដង។ ពិនិត្យថា {1, 2} ស្មើ {2, 1} ហើយ {1, 2} មិនស្មើ {1, 2, 3}។
  4. គូភ្លោះ bitmask។ ដាក់លេខមនុស្សប្រាំនាក់ពី 0 ដល់ 4 ហើយរក្សាទុកក្រុមនីមួយៗជា bitmask ដែលមនុស្ស id គឺ bit 1 << id។ បង្កើត mask signedUp និង mask paid គណនា "បានចុះឈ្មោះ ប៉ុន្តែមិនបានបង់ប្រាក់" ដោយ & និង ~ បន្ទាប់មក loop លើ bit ដើម្បីរាយបញ្ជីអ្នកណានៅក្នុងលទ្ធផល។
  5. ពិនិត្យសិទ្ធិ។ សរសេរ canDo(userPermissions, required) ដែលត្រឡប់ true តែនៅពេលសិទ្ធិ required ទាំងអស់មានវត្តមាន។ ប្រើ isSubset ហើយសាកល្បងជាមួយ set required ទទេ។
  6. គិតឲ្យជ្រៅជាងនេះ។ តើអ្នកនឹងរកធាតុដែលលេចឡើងក្នុង set ទាំងបី ក្នុងចំណោម set បីយ៉ាងដូចម្តេច? ជំនួយ៖ អនុវត្ត intersection ពីរដង។

Set ឆ្លើយ "អ្នកណានៅក្នុងក្រុមណា"។ បន្ទាប់យើងនឹងមើលលេខដែលរស់នៅក្នុង loop ដូចជាម្ជុលនាឡិកា ឬស្លាយនៃ carousel៖ នព្វន្ត Modular ពន្យល់ពី % អន្ទាក់លេខអវិជ្ជមាន និងរបៀបដែល check digit ចាប់កំហុសវាយខុសក្នុងលេខកាត។

ទិញកាហ្វេជូនខ្ញុំ

ចូលចិត្តមេរៀននេះមែនទេ? សូមពិចារណាទិញកាហ្វេជូនខ្ញុំមួយកែវ ដើម្បីគាំទ្រការបង្កើតមាតិកាឥតគិតថ្លៃបន្ថែមទៀត!