List (List class) เป็น indexable collection ที่ทำหน้าที่คล้ายกับข้อมูลประเภท array ในภาษาคอมพิวเตอร์อื่น ๆ เป็นการเก็บข้อมูลหลาย ๆ ตัว เป็นลำดับแถว สามารถกำหนดประเภทข้อมูลที่อยู่ภายใน List ได้ว่าจะเป็นข้อมูลประเภทไหน ตัวเลข ตัวอักษร หรือ Object กำหนดประเภทข้อมูลผ่าน Generic
การสร้างและประกาศข้อมูล List จะใช้เครื่องหมายวงเล็บก้ามปู [...]
เพื่อใส่สมาชิกภายในนั้น
void main() {
var myList = [1, 2, 3];
print(myList); // output → [1, 2, 3]
print(myList.length); // output → 3
print(myList.elementAt(0)); // output → 1
print(myList.elementAt(1)); // output → 2
print(myList.elementAt(2)); // output → 3
}
จากตัวอย่าง การประกาศโดยใช้ [...]
จะตีความเป็น type annotation ดังนี้
List<int> myList = [1, 2, 3];
ตัว myList ที่สร้างขึ้น จะเป็น List ที่จะเก็บเฉพาะข้อมูลที่เป็น int
เท่านั้น หากพยายามเพิ่มหรือแก้ไขข้อมูลที่ไม่ใช่ int
เข้าไป จะทำให้เกิด error ขึ้น
void main() {
List<int> myList = [1, 2, 3];
dynamic x = 10.5;
myList.add(x); // Unhandled exception: type 'double' is not a subtype of type 'int'
print(myList);
}
ในกรณีที่ต้องการให้ List เก็บข้อมูลแบบ dynamic
ให้ประกาศ Generic เป็น dynamic
แบบนี้
var myList1 = <dynamic>[1, 2, 3, 'ABC', 10.5];
List<dynamic> myList2 = [1, 2, 3, 'ABC', 10.5]; //same as myList1
หากต้องการสร้าง List ที่ไม่สามารถเปลี่ยนแปลงค่าได้ (แก้ไขค่า/เพิ่ม/ลด สมาชิกใน List) สำหรับไว้ใช้งาน ให้ใช้ keyword const
ในการประกาศ List
const myList1 = [0, 1, 2];
const List<int> myList2 = [0, 1, 2]; //same as myList1
var myList3 = const [0, 1, 2]; //same as myList1
var myList4 = const <int>[0, 1, 2]; //same as myList1
myList1.add(10); // error → Unsupported operation: Cannot add to an unmodifiable list
myList2.add(20); // error → Unsupported operation: Cannot add to an unmodifiable list
หากต้องการสร้าง unmodifiable list จาก list ที่มีอยู่แล้วในตัวแปรอื่น สามารถสร้างด้วย .unmodifiable()
constructor ตามตัวอย่าง
void main() {
var myList1 = <int>[1, 2, 3]; // normal list
myList1.add(30); //OK
var myList2 = List.unmodifiable(myList1); // use myList1 as init data
print(myList2); // output → [1, 2, 3, 30]
myList2.add(30); // error → Unsupported operation: Cannot add to an unmodifiable list
myList2[0] = 100; // error → Unsupported operation: Cannot modify an unmodifiable list
}
การสร้าง List ที่มีสมาชิกคงที่ ไม่สามารถเพิ่ม/ลด จำนวนสมาชิกใน List โดยการใช้ .from()
และ .filled()
constructor โดยกำหนดค่า growable: false
.from()
จะเป็นการสร้าง List จาก List ที่มีอยู่แล้ว ดู API เพิ่มเติม.filled()
จะเป็นการสร้าง List โดยเติมค่าเริ่มต้นเข้าไปตามจำนวนสมาชิกที่ต้องการ ดู API เพิ่มเติมตัวอย่างการใช้ .from()
ในการสร้างจาก List ที่มีอยู่แล้ว อาจเป็นตัวแปร หรือระบุ List ที่ต้องการสร้างลงไป
void main() {
var myList = List.from(<int>[1, 2, 3], growable: false);
print(myList); // output → [1, 2, 3]
myList[0] = 0; // modify element index 0 from 1 to zero
print(myList); // output → [0, 2, 3]
myList.add(4); // error → Unsupported operation: Cannot add to a fixed-length list
}
ตัวอย่างการใช้ .filled()
โดยต้องระบุค่าเริ่มต้นของสมาชิกใน List
void main() {
var myList1 = List.filled(3, 0, growable: false);
print(myList1); // output → [0, 0, 0]
myList1[0] = 10; // modify element index 0 from 0 to 10
print(myList1); // output → [10, 0, 0]
myList1.add(4); // error → Unsupported operation: Cannot add to a fixed-length list
}
ตำแหน่งของสมาชิกใน List จะเป็น zero-based indexing นั้นคือ สมาชิกตัวแรกจะมีค่า index เป็น 0 สามารถเข้าถึงด้วยคำสั่ง .elementAt(index)
หรือใช้วงเล็บก้ามปู [index]
ก็ได้แล้วแต่สะดวก
void main() {
var myList1 = [0, 1, 2];
print(myList1[0]); // output → 0
print(myList1[1]); // output → 1
print(myList1[2]); // output → 2
print(myList1[3]); // RangeError (index): Invalid value: Not in inclusive range 0..2: 3
}
ในตัวอย่าง ค่า index ของ myList1 จะมีค่าอยู่ที่ 0
ถึง myList1.length - 1
หากพยายามเข้าถึง index ที่ไม่มีอยู่จริงจะเกิด RangeError ขึ้น โปรดระวังในการใช้งาน
การแก้ไขค่าของสมาชิก สามารถทำโดยใช้เครื่องหมาย = ในการกำหนดค่าใหม่ของสมาชิกในตำแหน่ง index ที่ต้องการ
var myList1 = [0, 1, 2];
myList1[1] = 2;
myList1[2] = 4;
print(myList1); // output → [0, 2, 4]
ตัว List จะมีคำสั่งในการจัดการข้อมูลของสมาชิก ดังนี้
.add()
ใช้เพิ่มสมาชิกใหม่ 1 ตัว เข้าไปต่อท้าย ดู API เพิ่มเติม.addAll()
ใช้เพิ่มสมาชิกใหม่ที่เป็น List เข้าไปต่อท้าย ดู API เพิ่มเติม.insert()
ทำการแทรกที่ตำแหน่ง index ด้วยสมาชิก 1 ตัว สมาชิกเดิมที่ตำแหน่ง index จะถูกเลื่อนไป index + 1 ดู API เพิ่มเติม.insertAll()
ทำการแทรกที่ตำแหน่ง index ด้วย List ที่ต้องการ สมาชิกเดิมที่ตำแหน่ง index จะถูกเลื่อนไป index + .length
ของ List ที่แทรก ดู API เพิ่มเติม.remove()
ใช้ลบสมาชิกที่มีค่าตรงกับที่กำหนด ในกรณีที่มีข้อมูลซ้ำ จะลบตัวแรกที่พบแค่ตัวเดียว คืนค่า false
หากไม่เจอข้อมูลที่จะให้ลบ ดู API เพิ่มเติม.removeAt()
ใช้ลบสมาชิกตรงตำแหน่ง index ที่ระบุ หากทำสำเร็จจะคืนค่าเป็นสมาชิกตัวที่ลบ และจะมีผลทำให้ .length
มีค่าลดลง 1 สมาชิกที่อยู่หลังจาก index ที่ลบ จะถูกเลื่อนมาข้างหน้าแทนตัวที่ลบไป ดู API เพิ่มเติม.removeLast()
จะลบจากตัวสมาชิกที่อยู่ด้านหลังสุด หากทำสำเร็จจะคืนค่าเป็นสมาชิกตัวที่ลบ และจะมีผลทำให้ .length
มีค่าลดลง 1 ดู API เพิ่มเติม.removeRange()
ลบสมาชิกที่มีค่า index ในช่วงที่ระบุ เช่น list.removeRange(1, 4)
ผลคือจะลบสมาชิกที่ index เท่ากับ 1 2 และ 3 ทิ้งไป มีผลทำให้ .length
มีค่าลดลง 4-1=3
ดู API เพิ่มเติม.removeWhere()
ลบสมาชิก ทุกตัว ที่ตรงกับเงื่อนไขทดสอบ ดู API เพิ่มเติม.clear()
ลบสมาชิกทุกตัวทิ้ง มีผลทำให้ .length
เท่ากับ 0
ดู API เพิ่มเติม.replaceRange()
เป็นคำสั่งที่รวม 2 คำสั่งเข้าด้วยกันคือ .removeRange()
→ .insertAll()
มีข้อดีคือประสิทธิภาพดีกว่า ดู API เพิ่มเติม.sort()
เรียงลำดับสมาชิกใน List สามารถใช้การเรียงลำดับตามค่าปริยายของข้อมูลก็ได้ หรือจะใช้ Comparator ฟังก์ชั่น เพื่อกำหนดวิธีการเรียงลำดับก็ได้ ดู API เพิ่มเติม.shuffle()
เปลี่ยนลำดับ index ของสมาชิกแบบสุ่ม ดู API เพิ่มเติม Random().nextInt(List.length);
เพื่อเอาค่า index มาดึงข้อมูลดีกว่า Random class.sublist()
คืนค่าเป็น List ตามช่วงค่า index ที่ระบุ เช่น .sublist(1, 3)
จะคืน List ของสมาชิก index ที่ 1 และ 2 กลับมา หากไม่กำหนดค่า end index จะคืน List จนถึงสมาชิกตัวสุดท้าย ดู API เพิ่มเติม.indexOf()
.lastIndexOf()
.indexWhere()
.lastIndexWhere()
List รองรับการค้นหาค่าของสมาชิก และคืนค่า index ของสมาชิกที่ตรงกับค่าหรือเงื่อนไขที่ต้องการ
ในการค้นหา index ของสมาชิกใน List ที่มีค่าซ้ำ สามารถเพิ่มตำแหน่ง start index เพื่อข้ามไปตำแหน่งที่จะค้นหาถัดไป
ในกรณีที่ไม่เจอสิ่งที่ค้นหา จะคืนค่า -1
กลับมา
การค้นหาสมาชิกที่ต้องการใน List อยู่ตำแหน่ง index ที่เท่าไหร่ หากเป็นการหาค่าเป็นตรงไปตรงมา สามารถใช้ .indexOf()
และ .lastIndexOf()
.indexOf()
หาสมาชิกที่ตรงกับที่ระบุ หน้าไปหลัง จาก index 0
→ .length -1
ดูรายละเอียด API เพิ่มเติม.lastIndexOf()
หาสมาชิกที่ตรงกับที่ระบุ หลังไปหน้า จาก index .length -1
→ 0
จะมีทิศทางในการค้นหาตรงข้ามกับ .indexOf()
ดูรายละเอียด API เพิ่มเติมตัวอย่างการใช้ .indexOf()
ในการค้นหาสมาชิก โดยจะจำลองว่าหากมีสมาชิกที่ค่าซ้ำกัน จะค้นหาตัวต่อไปอย่างไร
void main() {
var myList = ['A', 'B', 'C', 'B', 'C'];
print(myList.indexOf('X')); // output → -1
print(myList.indexOf('A')); // output → 0
print(myList.indexOf('C')); // output → 2
// search duplicate value
var lastFound = myList.indexOf('B');
print(lastFound); // output → 1
print(myList.indexOf('B', lastFound + 1)); // output → 3
}
ตัวอย่างการใช้ .lastIndexOf()
ในการค้นหาสมาชิก จากหลังมาหน้า โดยจะจำลองว่าหากมีสมาชิกที่ค่าซ้ำกัน จะค้นหาตัวก่อนหน้าอย่างไร
void main() {
var myList = ['A', 'B', 'C', 'B', 'C'];
print(myList.lastIndexOf('X')); // output → -1
print(myList.lastIndexOf('A')); // output → 0
print(myList.lastIndexOf('C')); // output → 4
// search duplicate value
var lastFound = myList.lastIndexOf('B');
print(lastFound); // output → 3
print(myList.lastIndexOf('B', lastFound - 1)); // output → 1
}
การค้นหาที่ต้องเขียนโปรแกรมเพื่อตรวจสอบสมาชิกว่าตรงกับที่ต้องการหรือไม่ สามารถใช้ .indexWhere()
และ .lastIndexWhere()
ให้เขียนฟังก์ชั่นที่ทดสอบและส่งค่า boolean กลับมา โดยจะคืนค่า index ของสมาชิกที่ตรงกับเงื่อนไขที่กำหนด
ตัวอย่าง การค้นหาค่าสมาชิก ที่มีค่ามากกว่า 2 ที่เจอเป็นตัวแรก
void main() {
var myList = [0, 1, 2, 3, 4, 5, 6];
var foundIndex = myList.indexWhere((element) => element > 2);
print(foundIndex); // output → 3
}
ตัวอย่าง การค้นหาค่าสมาชิก ที่มีค่ามากกว่า 2 ที่เจอเป็นตัวสุดท้าย (ค้นหาจากหลังมาหน้า)
void main() {
var myList = [0, 1, 2, 3, 4, 5, 6];
var foundIndex = myList.lastIndexWhere((element) => element > 2);
print(foundIndex); // output → 6
}
เนื่องจากตัว .indexOf()
.lastIndexOf()
.indexWhere()
.lastIndexWhere()
ออกแบบมาเพื่อค้นหา ว่ามีสมาชิกใน List ตรงกับที่ค้นหาหรือไม่ ถ้าไม่เจอก็ได้ค่า -1
กลับมา การที่พยายามเอาไปทดสอบเพื่อหาสมาชิกทุกตัวที่เหลือว่ามี index ใดบ้างที่ตรง หาก List มีขนาดใหญ่ จะเกิดปัญหาเรื่องประสิทธิภาพขึ้น แนะนำว่าใช้คำสั่ง for()
เพื่อไล่ตรวจสอบสมาชิกทุกตัวจะดีกว่า
void main() {
var myList = [0, 1, 2, 3, 4, 5, 6];
for (int index = 0; index < myList.length; ++index) {
if (myList[index] > 2) {
print(index);
}
}
}
ผลที่ได้
3
4
5
6
+
หากต้องการสร้าง List ใหม่ ที่เกิด List จำนวน 2 ตัวเข้าด้วยกัน สามารถใช้ +
ในการเชื่อมต่อ List ได้
void main() {
var myList1 = [1, 2];
var myList2 = [3, 4];
var myList12 = myList1 + myList2;
print(myList12); // output → [1, 2, 3, 4]
}
ใช้เพื่อสร้าง List ใหม่เท่านั้น หากต้องการจะเอาไปต่อ List เดิม อย่าใช้วิธีนี้
❎myList1 = myList1 + myList2;
ให้ใช้ ✅ myList1.addAll(myList2);
...
เพื่อใช้เพิ่มสมาชิกใน List ใหม่ ด้วย List ที่มีอยู่นอกจากการใช้ .addAll()
และ +
เพื่อทำงานกับตัวแปรข้อมูล List แล้ว ยังสามารถใช้ ...
เพื่ออ้างถึงตัวแปร List ที่จะนำไปใส่ใน List ใหม่ที่ต้องการสร้างได้อีกด้วย ซึ่งบางครั้งก็สะดวกในการเขียนโปรแกรม เนื่องจากสั้นและเข้าใจได้ง่าย
void main() {
var myList1 = [1, 2];
var myList2 = [10, 20, ...myList1];
print(myList2); // output → [10, 20, 1, 2]
var myList3 = [...myList1, ...myList2];
print(myList3); // output → [1, 2, 10, 20, 1, 2]
}
จากตัวอย่างข้างบน สามารถเขียนโดยไม่ใช้ ...
เพื่อให้ผลเหมือนกันดังนี้
void main() {
var myList1 = [1, 2];
var myList2 = [10, 20];
myList2.addAll(myList1);
print(myList2); // output → [10, 20, 1, 2]
var myList3 = myList1 + myList2;
print(myList3); // output → [1, 2, 10, 20, 1, 2]
}
ดูข้อมูลเพิ่มเติมเกี่ยวกับ Spread Operator
==
อันนี้อาจดูแปลก ๆ หน่อย😅ที่ไม่สามารถใช้ ==
เปรียบเทียบระหว่าง List ได้ แม้จะมีสมาชิกเหมือนกันทุกประการ แต่ใน API บอกไว้ว่า
Whether this list is equal to
other
.
Lists are, by default, only equal to themselves. Even ifother
is also a list, the equality comparison does not compare the elements of the two lists.
void main() {
var myList1 = [1, 2];
var myList2 = List.from(myList1);
var myList3 = [1, 2];
print(myList1); // output → [1, 2]
print(myList2); // output → [1, 2]
print(myList1 == myList2); // output → false
print(myList1 == myList3); // output → false
print(myList1 == myList1); // output → true
var myList4 = myList1;
print(myList1 == myList4); // output → true
}
จากตัวอย่างจะเห็นว่า ==
เอาไว้ทดสอบว่าตัวแปรสองตัว อ้างอิงไปที่ตัว List เดียวกันหรือไม่เท่านั้น (ในตัวอย่างคือ myList1
กับ myList4
)
อ้างอิงตาม Dart 3.5.0 จะใช้ List เป็นประเภทข้อมูลที่เก็บเป็นแถว แต่มีแค่มิติเดียว หากต้องการใช้งานแบบหลายมิติ จำเป็นต้องใช้วิธีการประกาศแบบ List ใน List ซ้อนกันอีกที ตัวอย่างการสร้าง List แบบ 2 มิติ
void main() {
var array2d = [
[1, 2],
[3, 4]
];
print(array2d[0][0]); // output → 1
print(array2d[0][1]); // output → 2
print(array2d[1][0]); // output → 3
print(array2d[1][1]); // output → 4
}
หากต้องการเขียนใช้งานใสรูปแบบที่เคยใช้ในภาษาอื่น เช่น array2d(1, 0)
array2d[1, 0]
แบบนี้จำเป็นต้องเขียน Class ขึ้นมาจัดการเอง หรืออาจจะไปลองดูใน Dart Packages ในเว็บ pub.dev ว่ามีใครที่สร้างเอาไว้บ้างหรือเปล่า
เนื่องจาก List สามารถใส่ข้อมูลซ้ำได้ หากต้องการใช้ข้อมูลของ List ที่เป็นค่าที่ตัดตัวซ้ำออกไป วิธีการที่เขียนโปรแกรมสั้น และสะดวก สามารถทำได้โดยแปลงจาก List → Set → List เนื่องจาก Set เป็น collection ที่ไม่มีการเก็บข้อมูลที่ซ้ำกัน เมื่อแปลงจาก List ที่มีสมาชิกข้อมูลซ้ำกัน มันจะตัดออกเหลือแค่ตัวเดียว
void main() {
var myList = [0, 1, 2, 1, 2, 1, 2, 3];
var mySet = Set.from(myList); // alternate method → myList.toSet()
var resultList = mySet.toList();
print(resultList); // output → [0, 1, 2, 3]
}
วิธีนี้เหมาะกับการแปลงเพื่อใช้งานเล็กน้อย ถ้าเป็นไปได้การเอาผลของ Set ที่ได้จากการแปลง List ไปใช่ต่อเลยจะช่วยประหยัดหน่วยความจำ
ในกรณี List มีขนาดใหญ่มาก ๆ ควรเขียนคำสั่งจัดการเองเลยอาจมีประสิทธิภาพดีกว่า