การหมุนลำดับข้อมูลใน ListView ด้วย Collections.rotate()
ตัวอย่างนี้สาธิตการใช้ Collections.rotate() เพื่อเลื่อนตำแหน่งข้อมูลใน ArrayList แบบวนซ้ำ (Circular shift) ก่อนแสดงใน ListView
ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่
สร้างโปรเจกต์ Android ใหม่ใน Android Studio
ขั้นตอนที่ 2: ออกแบบ Layout (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
android:padding="16dp">
<EditText
android:id="@+id/etName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="ป้อนชื่อ" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="horizontal">
<Button android:id="@+id/btnSave" android:text="บันทึก" android:layout_width="wrap_content" android:layout_height="wrap_content" />
<Button android:id="@+id/btnRefresh" android:text="รีเฟรช" android:layout_width="wrap_content" android:layout_height="wrap_content" />
</LinearLayout>
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp">
</ListView>
</LinearLayout>
ขั้นตอนที่ 3: MainActivity.java (แก้ไข Logic ให้ถูกต้อง)
package com.example.myapplication;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class MainActivity extends AppCompatActivity {
private EditText etName;
private ListView listView;
private ArrayAdapter<String> adapter;
private ArrayList<String> arrayList = new ArrayList<>();
private Set<String> uniqueSet = new HashSet<>();
private static final int ROTATE_DISTANCE = 2; // เลื่อน 2 ตำแหน่ง
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etName = findViewById(R.id.etName);
listView = findViewById(R.id.listView);
findViewById(R.id.btnRefresh).setOnClickListener(v -> {
if (adapter != null) {
adapter.notifyDataSetChanged();
listView.invalidateViews();
listView.refreshDrawableState();
}
});
findViewById(R.id.btnSave).setOnClickListener(v -> {
String input = etName.getText().toString().trim();
if (!input.isEmpty()) {
uniqueSet.add(input);
arrayList.clear();
arrayList.addAll(uniqueSet);
// จุดสำคัญ: ใช้ Collections.rotate() เลื่อนตำแหน่ง
// distance > 0: เลื่อนไปขวา (ท้ายไปหน้า)
// distance < 0: เลื่อนไปซ้าย (หน้าไปท้าย)
if (!arrayList.isEmpty()) {
Collections.rotate(arrayList, ROTATE_DISTANCE);
}
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, arrayList);
listView.setAdapter(adapter);
Toast.makeText(this, "บันทึกสำเร็จ (หมุน " + ROTATE_DISTANCE + " ตำแหน่ง)", Toast.LENGTH_SHORT).show();
} else {
etName.setError("กรุณาป้อนชื่อ");
}
});
}
}
คำอธิบาย Collections.rotate()
Collections.rotate(list, distance);
- เลื่อนองค์ประกอบใน List แบบ Circular (วนกลับมาที่อีกด้าน)
- distance > 0: เลื่อนไปขวา (Right rotate) - องค์ประกอบท้ายไปอยู่หน้า
- distance < 0: เลื่อนไปซ้าย (Left rotate) - องค์ประกอบหน้าไปอยู่ท้าย
- distance = 0 หรือ distance % size == 0: ไม่เปลี่ยนแปลง
- Time Complexity: O(n) | Space: O(1) - in-place algorithm
- ทำงานได้กับ List ใดๆ ที่ implements List interface และรองรับ RandomAccess
ตัวอย่างการทำงาน (ROTATE_DISTANCE = 2)
ข้อมูลใน Set: {"A", "B", "C", "D", "E"} → ArrayList (ก่อน rotate): [A, B, C, D, E]
| การกระทำ | ArrayList ก่อน rotate | หลัง rotate(2) - ขวา 2 | หลัง rotate(-1) - ซ้าย 1 |
|---|---|---|---|
| เพิ่ม A | [A] | [A] | [A] |
| เพิ่ม B | [A, B] | [A, B] | [B, A] |
| เพิ่ม C | [A, B, C] | [B, C, A] | [B, C, A] |
| เพิ่ม D | [A, B, C, D] | [C, D, A, B] | [B, C, D, A] |
| เพิ่ม E | [A, B, C, D, E] | [D, E, A, B, C] | [B, C, D, E, A] |
การคำนวณ Rotate (Right rotate 2)
Index เดิม: 0 1 2 3 4
Value: A B C D E
↓ ↓ ↓ ↓ ↓ (เลื่อนขวา 2)
Index ใหม่: 2 3 4 0 1
Value: A B C D E
↓
ผลลัพธ์: D E A B C
Index: 0 1 2 3 4
กรณีการใช้งานจริง
- Circular Buffer / Ring Buffer - จัดการ buffer ขนาดคงที่
- Load Balancing - สลับ Server/Worker แบบ Round-robin
- Game Development - หมุนตำแหน่งผู้เล่น, หมุนการ์ด
- Animation - เลื่อนรายการใน Carousel/Marquee
- Scheduling - Round-robin task scheduling
- Cryptography - Bit rotation (แต่ระดับ bit)
การ Implement เอง (Manual Rotate)
public static <T> void rotateManual(List<T> list, int distance) {
if (list == null || list.isEmpty()) return;
int size = list.size();
distance = distance % size;
if (distance < 0) distance += size;
if (distance == 0) return;
// ใช้ Collections.reverse() 3 ครั้ง (Efficient in-place)
Collections.reverse(list);
Collections.reverse(list.subList(0, distance));
Collections.reverse(list.subList(distance, size));
}
ข้อควรระวัง
- rotate() แก้ไข List เดิม (mutating) - copy ก่อนหากต้องการเก็บต้นฉบับ
- ทำงานได้ดีที่สุดกับ RandomAccess List (ArrayList) - LinkedList จะช้ากว่า
- distance อาจมากกว่า size - ใช้ modulo เพื่อปรับให้อยู่ในช่วง
- Empty list หรือ size=1 → rotate ไม่มีผล
เปรียบเทียบ Collections Methods สำหรับจัดลำดับ
| Method | การกระทำ | ตัวอย่าง [A,B,C,D,E] |
|---|---|---|
| sort() | เรียงน้อยไปมาก | [A,B,C,D,E] |
| reverse() | กลับลำดับ | [E,D,C,B,A] |
| shuffle() | สุ่มลำดับ | [C,A,E,B,D] |
| rotate(list, 2) | เลื่อนขวา 2 | [D,E,A,B,C] |
| rotate(list, -2) | เลื่อนซ้าย 2 | [C,D,E,A,B] |