Cho một mảng gồm n Đối tượng, giả sử nó là một mảng chuỗi và nó có các giá trị sau:
foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";
Tôi phải làm gì để xóa / loại bỏ tất cả các chuỗi / đối tượng bằng "a" trong mảng?
Cho một mảng gồm n Đối tượng, giả sử nó là một mảng chuỗi và nó có các giá trị sau:
foo[0] = "a";
foo[1] = "cc";
foo[2] = "a";
foo[3] = "dd";
Tôi phải làm gì để xóa / loại bỏ tất cả các chuỗi / đối tượng bằng "a" trong mảng?
Câu trả lời:
[Nếu bạn muốn một số mã sẵn sàng sử dụng, vui lòng cuộn đến "Edit3" của tôi (sau khi cắt). Phần còn lại ở đây dành cho hậu thế.]
Để xác thực ý tưởng của Dustman :
List<String> list = new ArrayList<String>(Arrays.asList(array));
list.removeAll(Arrays.asList("a"));
array = list.toArray(array);
Chỉnh sửa: Tôi bây giờ sử dụng Arrays.asList
thay vì Collections.singleton
: singleton được giới hạn trong một entry, trong khi asList
cách tiếp cận cho phép bạn thêm các chuỗi khác để lọc ra sau: Arrays.asList("a", "b", "c")
.
Edit2: Cách tiếp cận trên vẫn giữ nguyên mảng (vì vậy mảng vẫn có cùng độ dài); phần tử sau phần tử cuối cùng được đặt thành null. Nếu bạn muốn một mảng mới có kích thước chính xác như yêu cầu, hãy sử dụng cái này thay thế:
array = list.toArray(new String[0]);
Chỉnh sửa3: Nếu bạn sử dụng mã này thường xuyên trong cùng một lớp, bạn có thể muốn xem xét thêm mã này vào lớp của mình:
private static final String[] EMPTY_STRING_ARRAY = new String[0];
Sau đó, hàm trở thành:
List<String> list = new ArrayList<>();
Collections.addAll(list, array);
list.removeAll(Arrays.asList("a"));
array = list.toArray(EMPTY_STRING_ARRAY);
Sau đó, điều này sẽ ngừng xả rác vào đống của bạn với các mảng chuỗi trống vô dụng mà nếu không sẽ được chỉnh sửa new
mỗi khi hàm của bạn được gọi.
Đề xuất của người hoài nghi (xem phần bình luận) cũng sẽ giúp giải quyết vấn đề xả rác bừa bãi, và để công bằng, tôi nên đề cập đến nó:
array = list.toArray(new String[list.size()]);
Tôi thích cách tiếp cận của mình hơn, vì có thể sai kích thước rõ ràng dễ dàng hơn (ví dụ: gọi size()
nhầm danh sách).
Một thay thế trong Java 8:
String[] filteredArray = Arrays.stream(array)
.filter(e -> !e.equals(foo)).toArray(String[]::new);
Stream.of(foo).filter(s -> ! s.equals("a")).toArray()
là đủ.
Tạo List
mảng với Arrays.asList()
và gọi remove()
tất cả các phần tử thích hợp. Sau đó, hãy gọi toArray()
vào 'Danh sách' để quay trở lại một mảng.
Hiệu suất không quá khủng khiếp, nhưng nếu bạn đóng gói nó đúng cách, bạn luôn có thể làm điều gì đó nhanh hơn sau này.
Arrays.asList()
không hỗ trợ remove()
. Vậy câu trả lời này có hoàn toàn không hợp lệ không? Có vẻ như một số nhận xét đã bị xóa, vì vậy tôi không biết liệu điều này có được thảo luận hay không.
Bạn luôn có thể làm:
int i, j;
for (i = j = 0; j < foo.length; ++j)
if (!"a".equals(foo[j])) foo[i++] = foo[j];
foo = Arrays.copyOf(foo, i);
Bạn có thể sử dụng thư viện bên ngoài:
org.apache.commons.lang.ArrayUtils.remove(java.lang.Object[] array, int index)
Nó nằm trong dự án Apache Commons Lang http://commons.apache.org/lang/
ArrayUtils.removeElement(boolean[] array, boolean element)
cũng rất hữu ích.
Nếu bạn cần xóa nhiều phần tử khỏi mảng mà không chuyển đổi nó thành List
cũng như tạo mảng bổ sung, bạn có thể thực hiện việc đó trong O (n) mà không phụ thuộc vào số lượng mục cần xóa.
Đây, a
là mảng ban đầu, int... r
là các chỉ số (vị trí) có thứ tự riêng biệt của các phần tử cần loại bỏ:
public int removeItems(Object[] a, int... r) {
int shift = 0;
for (int i = 0; i < a.length; i++) {
if (shift < r.length && i == r[shift]) // i-th item needs to be removed
shift++; // increment `shift`
else
a[i - shift] = a[i]; // move i-th item `shift` positions left
}
for (int i = a.length - shift; i < a.length; i++)
a[i] = null; // replace remaining items by nulls
return a.length - shift; // return new "length"
}
Thử nghiệm nhỏ:
String[] a = {"0", "1", "2", "3", "4"};
removeItems(a, 0, 3, 4); // remove 0-th, 3-rd and 4-th items
System.out.println(Arrays.asList(a)); // [1, 2, null, null, null]
Trong nhiệm vụ của bạn, trước tiên bạn có thể quét mảng để thu thập vị trí của "a", sau đó gọi removeItems()
.
Một cái gì đó về tạo danh sách của nó sau đó xóa sau đó quay lại một mảng khiến tôi không hiểu. Chưa được thử nghiệm, nhưng tôi nghĩ rằng phần sau sẽ hoạt động tốt hơn. Có, tôi có lẽ đang tối ưu hóa trước quá mức.
boolean [] deleteItem = new boolean[arr.length];
int size=0;
for(int i=0;i<arr.length;i==){
if(arr[i].equals("a")){
deleteItem[i]=true;
}
else{
deleteItem[i]=false;
size++;
}
}
String[] newArr=new String[size];
int index=0;
for(int i=0;i<arr.length;i++){
if(!deleteItem[i]){
newArr[index++]=arr[i];
}
}
Tôi nhận ra rằng đây là một bài viết rất cũ, nhưng một số câu trả lời ở đây đã giúp tôi giải đáp, vì vậy đây là giá trị của tôi!
Tôi đã vật lộn để điều này hoạt động trong một thời gian trước khi xác nhận rằng mảng mà tôi đang viết lại cần được thay đổi kích thước, trừ khi các thay đổi được thực hiện đối với ArrayList
kích thước danh sách không thay đổi.
Nếu cái ArrayList
mà bạn đang sửa đổi kết thúc với nhiều hơn hoặc ít phần tử hơn nó bắt đầu, thì dòng List.toArray()
sẽ gây ra một ngoại lệ, vì vậy bạn cần một cái gì đó giống như List.toArray(new String[] {})
hoặc List.toArray(new String[0])
để tạo một mảng với kích thước mới (đúng).
Nghe có vẻ hiển nhiên bây giờ tôi biết điều đó. Không quá rõ ràng đối với một người mới sử dụng Android / Java, những người đang nắm bắt các cấu trúc mã mới và không quen thuộc và không rõ ràng từ một số bài đăng trước đó ở đây, vì vậy tôi chỉ muốn làm rõ điểm này cho bất kỳ ai khác đang vò đầu bứt tai hàng giờ như tôi. !
Có rất nhiều câu trả lời ở đây - vấn đề như tôi thấy là bạn không nói TẠI SAO bạn đang sử dụng mảng thay vì tập hợp, vì vậy hãy để tôi đề xuất một vài lý do và giải pháp nào sẽ áp dụng (Hầu hết các giải pháp đã được trả lời trong các câu hỏi khác ở đây, vì vậy tôi sẽ không đi vào quá nhiều chi tiết):
lý do: Bạn không biết gói bộ sưu tập tồn tại hoặc không tin tưởng nó
giải pháp: Sử dụng một bộ sưu tập.
Nếu bạn định thêm / xóa từ giữa, hãy sử dụng LinkedList. Nếu bạn thực sự lo lắng về kích thước hoặc thường xuyên lập chỉ mục vào giữa bộ sưu tập, hãy sử dụng ArrayList. Cả hai điều này phải có hoạt động xóa.
lý do: Bạn lo lắng về kích thước hoặc muốn kiểm soát việc cấp phát bộ nhớ
giải pháp: Sử dụng ArrayList với kích thước ban đầu cụ thể.
ArrayList chỉ đơn giản là một mảng có thể tự mở rộng, nhưng không phải lúc nào nó cũng cần phải làm như vậy. Sẽ rất thông minh khi thêm / bớt các mục, nhưng một lần nữa nếu bạn đang chèn / xóa NHIỀU từ giữa, hãy sử dụng LinkedList.
lý do: Bạn có một mảng đi vào và một mảng đi ra - vì vậy bạn muốn hoạt động trên một mảng
giải pháp: Chuyển đổi nó thành ArrayList, xóa mục và chuyển đổi lại
lý do: Bạn nghĩ rằng bạn có thể viết mã tốt hơn nếu bạn tự làm
giải pháp: bạn không thể, hãy sử dụng Mảng hoặc danh sách Liên kết.
Lý do: đây là bài tập của lớp và bạn không được phép hoặc bạn không có quyền truy cập vào apis tuyển tập vì lý do nào đó
giả định: Bạn cần mảng mới có "kích thước" chính xác
giải pháp: Quét mảng để tìm các mục phù hợp và đếm chúng. Tạo một mảng mới có kích thước chính xác (kích thước ban đầu - số lượng kết quả phù hợp). sử dụng System.arraycopy nhiều lần để sao chép từng nhóm mục bạn muốn giữ lại vào Mảng mới của mình. Nếu đây là bài tập của lớp và bạn không thể sử dụng System.arraycopy, chỉ cần sao chép chúng lần lượt bằng tay trong một vòng lặp nhưng đừng bao giờ làm điều này trong mã sản xuất vì nó chậm hơn nhiều. (Các giải pháp này đều được trình bày chi tiết trong các câu trả lời khác)
lý do: bạn cần chạy kim loại trần
giả định: bạn PHẢI phân bổ không gian không cần thiết hoặc mất quá nhiều thời gian
giả định: Bạn đang theo dõi kích thước được sử dụng trong mảng (chiều dài) một cách riêng biệt vì nếu không, bạn phải phân bổ lại mảng của mình để xóa / chèn.
Ví dụ về lý do tại sao bạn có thể muốn làm điều này: một mảng nguyên thủy đơn lẻ (Giả sử giá trị int) đang chiếm một phần đáng kể ram của bạn - như 50%! ArrayList sẽ buộc chúng vào danh sách các con trỏ tới các đối tượng Integer sẽ sử dụng một vài lần dung lượng bộ nhớ đó.
giải pháp: Lặp lại mảng của bạn và bất cứ khi nào bạn tìm thấy một phần tử cần xóa (hãy gọi nó là phần tử n), hãy sử dụng System.arraycopy để sao chép phần đuôi của mảng qua phần tử "đã xóa" (Nguồn và Đích là cùng một mảng) - nó đủ thông minh để thực hiện sao chép theo đúng hướng để bộ nhớ không tự ghi đè:
System.arraycopy (ary, n + 1, ary, n, length-n) chiều dài--;
Bạn có thể muốn thông minh hơn điều này nếu bạn đang xóa nhiều phần tử cùng một lúc. Bạn sẽ chỉ di chuyển khu vực giữa một "khớp" và tiếp theo thay vì toàn bộ phần đuôi và như mọi khi, tránh di chuyển bất kỳ đoạn nào hai lần.
Trong trường hợp cuối cùng này, bạn hoàn toàn phải tự mình thực hiện công việc và sử dụng System.arraycopy thực sự là cách duy nhất để làm điều đó vì nó sẽ chọn cách tốt nhất có thể để di chuyển bộ nhớ cho kiến trúc máy tính của bạn - nó sẽ nhanh hơn nhiều lần hơn bất kỳ mã nào bạn có thể tự viết một cách hợp lý.
BIÊN TẬP:
Điểm có rỗng trong mảng đã bị xóa. Xin lỗi vì nhận xét của tôi.
Nguyên:
Ehm ... dòng
array = list.toArray(array);
thay thế tất cả các khoảng trống trong mảng có phần tử bị loại bỏ bằng null . Điều này có thể nguy hiểm , vì các phần tử bị loại bỏ, nhưng độ dài của mảng vẫn giữ nguyên!
Nếu bạn muốn tránh điều này, hãy sử dụng một Mảng mới làm tham số cho toArray (). Nếu bạn không muốn sử dụng removeAll, một Set sẽ là một lựa chọn thay thế:
String[] array = new String[] { "a", "bc" ,"dc" ,"a", "ef" };
System.out.println(Arrays.toString(array));
Set<String> asSet = new HashSet<String>(Arrays.asList(array));
asSet.remove("a");
array = asSet.toArray(new String[] {});
System.out.println(Arrays.toString(array));
Cung cấp:
[a, bc, dc, a, ef]
[dc, ef, bc]
Đâu là câu trả lời được chấp nhận hiện tại từ Chris Yester Young đầu ra:
[a, bc, dc, a, ef]
[bc, dc, ef, null, ef]
với mã
String[] array = new String[] { "a", "bc" ,"dc" ,"a", "ef" };
System.out.println(Arrays.toString(array));
List<String> list = new ArrayList<String>(Arrays.asList(array));
list.removeAll(Arrays.asList("a"));
array = list.toArray(array);
System.out.println(Arrays.toString(array));
không có bất kỳ giá trị rỗng nào bị bỏ lại.
Đóng góp nhỏ của tôi cho vấn đề này.
public class DeleteElementFromArray {
public static String foo[] = {"a","cc","a","dd"};
public static String search = "a";
public static void main(String[] args) {
long stop = 0;
long time = 0;
long start = 0;
System.out.println("Searched value in Array is: "+search);
System.out.println("foo length before is: "+foo.length);
for(int i=0;i<foo.length;i++){ System.out.println("foo["+i+"] = "+foo[i]);}
System.out.println("==============================================================");
start = System.nanoTime();
foo = removeElementfromArray(search, foo);
stop = System.nanoTime();
time = stop - start;
System.out.println("Equal search took in nano seconds = "+time);
System.out.println("==========================================================");
for(int i=0;i<foo.length;i++){ System.out.println("foo["+i+"] = "+foo[i]);}
}
public static String[] removeElementfromArray( String toSearchfor, String arr[] ){
int i = 0;
int t = 0;
String tmp1[] = new String[arr.length];
for(;i<arr.length;i++){
if(arr[i] == toSearchfor){
i++;
}
tmp1[t] = arr[i];
t++;
}
String tmp2[] = new String[arr.length-t];
System.arraycopy(tmp1, 0, tmp2, 0, tmp2.length);
arr = tmp2; tmp1 = null; tmp2 = null;
return arr;
}
}
Nó phụ thuộc vào những gì bạn có nghĩa là "loại bỏ"? Mảng là một cấu trúc có kích thước cố định - bạn không thể thay đổi số lượng phần tử trong đó. Vì vậy, bạn có thể a) tạo một mảng mới, ngắn hơn, không có các phần tử mà bạn không muốn hoặc b) gán các mục bạn không muốn cho một cái gì đó cho biết trạng thái 'trống' của chúng; thường là null nếu bạn không làm việc với các nguyên thủy.
Trong trường hợp đầu tiên, hãy tạo Danh sách từ mảng, xóa các phần tử và tạo một mảng mới từ danh sách. Nếu hiệu suất là quan trọng, hãy lặp lại mảng chỉ định bất kỳ phần tử nào không nên bị xóa vào danh sách, sau đó tạo một mảng mới từ danh sách. Trong trường hợp thứ hai, chỉ cần đi qua và gán null cho các mục nhập mảng.
Arrgh, tôi không thể nhận mã hiển thị chính xác. Xin lỗi, tôi đã làm cho nó hoạt động. Xin lỗi một lần nữa, tôi không nghĩ rằng tôi đã đọc câu hỏi một cách chính xác.
String foo[] = {"a","cc","a","dd"},
remove = "a";
boolean gaps[] = new boolean[foo.length];
int newlength = 0;
for (int c = 0; c<foo.length; c++)
{
if (foo[c].equals(remove))
{
gaps[c] = true;
newlength++;
}
else
gaps[c] = false;
System.out.println(foo[c]);
}
String newString[] = new String[newlength];
System.out.println("");
for (int c1=0, c2=0; c1<foo.length; c1++)
{
if (!gaps[c1])
{
newString[c2] = foo[c1];
System.out.println(newString[c2]);
c2++;
}
}
Trong một mảng các chuỗi như
String name = 'abcdeafbde' // có thể giống như String name = 'aa bb cde aa f bb de'
Tôi xây dựng lớp sau
class clearname{
def parts
def tv
public def str = ''
String name
clearname(String name){
this.name = name
this.parts = this.name.split(" ")
this.tv = this.parts.size()
}
public String cleared(){
int i
int k
int j=0
for(i=0;i<tv;i++){
for(k=0;k<tv;k++){
if(this.parts[k] == this.parts[i] && k!=i){
this.parts[k] = '';
j++
}
}
}
def str = ''
for(i=0;i<tv;i++){
if(this.parts[i]!='')
this.str += this.parts[i].trim()+' '
}
return this.str
}}
return new clearname(name).cleared()
nhận được kết quả này
abcdef
hy vọng mã này sẽ giúp được mọi người.
Nếu nó không quan trọng thứ tự của các phần tử. bạn có thể hoán đổi giữa các phần tử foo [x] và foo [0], sau đó gọi foo.drop (1).
foo.drop(n)
loại bỏ (n) phần tử đầu tiên khỏi mảng.
Tôi đoán đây là cách đơn giản nhất và hiệu quả về tài nguyên.
PS : indexOf
có thể được thực hiện theo nhiều cách, đây là phiên bản của tôi.
Integer indexOf(String[] arr, String value){
for(Integer i = 0 ; i < arr.length; i++ )
if(arr[i] == value)
return i; // return the index of the element
return -1 // otherwise -1
}
while (true) {
Integer i;
i = indexOf(foo,"a")
if (i == -1) break;
foo[i] = foo[0]; // preserve foo[0]
foo.drop(1);
}