检查已排序的数组是否有重复项

时间:2016-07-25 00:48:27

标签: java android arrays

我确实有一个排序数组,我想检查重复的托管。问题是我需要知道副本的位置是多维数组,我也需要删除第二个条目。最后,我必须有一个数组填充值,所以只需用一些虚拟的工作覆盖重复项。我已经阅读了关于Array.utils做这个伎俩但我没有导入任何其他库并且Array.utils未被识别的内容,因此我无法导入该内容。

我也试着自己写一个小功能

        Integer iIndex = 1;
   while (keepRunning2){
        if(phoneNameNumber[iIndex][0].equals(phoneNameNumber[iIndex-1][0])){
            keepRunning = true;
            tmp = new String[phoneNameNumber.length-1][2];
            int k = 0;
            int t=0;
            while(keepRunning){
                Log.wtf("running",String.valueOf(iIndex) + ":" + String.valueOf(k));
                tmp[t][0] = phoneNameNumber[k][0];
                tmp[t][1] = phoneNameNumber[k][1];
                if(k!=i-1){
                    k++;
                    t++;
                }else{
                    k=k+2;
                    t++;
                }
                if(t==tmp.length-1)
                    keepRunning=false;

            }
            phoneNameNumber = null;
            phoneNameNumber = new String[tmp.length][2];
            phoneNameNumber = tmp;
        }
        if(!(iIndex < phoneNameNumber.length-1)){
            keepRunning2 = false;
        }
        iIndex++;
    }

Buuuut ......首先需要10年时间来完成这个,因为这是一个应用程序的用户界面,你可以看到它应该更快+由于某种原因,在处理完所有这一切后,它会跳回到keeppRunning2&#39; d永远不会被设置为false。

有人知道解决方案吗?

如果某人想知道数据的来源:继承人的活动

import android.app.ActionBar;
import android.app.Activity;
import android.app.DialogFragment;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CheckedTextView;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RadioGroup;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import java.sql.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ExecutionException;

/**
 * Created by **** on 19.07.2016.
 */
public class newChatActivity extends Activity implements       View.OnClickListener,AdapterView.OnItemSelectedListener{

Button bCreateChat;
Button bCancelChat;
EditText tchat_name;
//EditText tmembers;
CheckBox cBoxPrivateChat;
Spinner memberSpinner;
String members = "";
String lastContactName = "";
List<String> nameList,number;
String[][]phoneNameNumber,tmp;
String[] sortedNames;
Integer i = 0;
Integer memberCount = 0;
Boolean keepRunning = true;
Boolean keepRunning2 = true;

private static final String[] PROJECTION = new String[] {
        ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
        ContactsContract.Contacts.DISPLAY_NAME,
        ContactsContract.CommonDataKinds.Phone.NUMBER
};



@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.new_chat);
    setTitle("Add New Chat");

    bCreateChat = (Button) findViewById(R.id.bCreateChat);
    bCancelChat = (Button) findViewById(R.id.bChatCance);
    tchat_name = (EditText) findViewById(R.id.tchat_name);
    cBoxPrivateChat = (CheckBox) findViewById(R.id.cBoxprivChat);
    memberSpinner = (Spinner) findViewById(R.id.memberSpinner);


    bCreateChat.setOnClickListener(this);
    bCancelChat.setOnClickListener(this);

    loadAllContacts();
    sortedNames = new String[phoneNameNumber.length];
    Integer iIndex = 1;
   while (keepRunning2){
        if(phoneNameNumber[iIndex][0].equals(phoneNameNumber[iIndex-1][0])){
            keepRunning = true;
            tmp = new String[phoneNameNumber.length-1][2];
            int k = 0;
            int t=0;
            while(keepRunning){
                Log.wtf("running",String.valueOf(iIndex) + ":" + String.valueOf(k));
                tmp[t][0] = phoneNameNumber[k][0];
                tmp[t][1] = phoneNameNumber[k][1];
                if(k!=i-1){
                    k++;
                    t++;
                }else{
                    k=k+2;
                    t++;
                }
                if(t==tmp.length-1)
                    keepRunning=false;


            }
            phoneNameNumber = null;
            phoneNameNumber = new String[tmp.length][2];
            phoneNameNumber = tmp;
        }
        if(!(iIndex < phoneNameNumber.length-1)){
            keepRunning2 = false;
        }
        iIndex++;
    }

    for(int i = 0;i<phoneNameNumber.length;i++){
        sortedNames[i] = phoneNameNumber[i][0];
    }
    ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item,sortedNames);
    spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    memberSpinner.setAdapter(spinnerAdapter);
    memberSpinner.setOnItemSelectedListener(this);



}


@Override
public void onClick(View v) {
    switch (v.getId()){
        case R.id.bCreateChat:
                if (!tchat_name.getText().toString().isEmpty()&&!members.isEmpty()) {
                    if(cBoxPrivateChat.isChecked()){
                        createChat("name=" + tchat_name.getText().toString() + "&members=" + members + ScrollingActivity.Identifier + "#");
                    }
                } else{
                    Toast.makeText(this,"Keine Daten Eingegeben",Toast.LENGTH_SHORT).show();
                }
            break;
        case R.id.bChatCance:
            this.finish();
            break;
        default:
            if(v.getId() > 2000000 ){
                members = members.replace("#" + number.get(v.getId() - 2000000) + "#","");
                TextView delText = (TextView) findViewById(v.getId());
                delText.setVisibility(View.GONE);
                memberCount = memberCount - 1;
                if(memberCount <= 1){
                    cBoxPrivateChat.setEnabled(true);
                }
            }
    }
}

public void createChat(String Data){
    try {
        Boolean b = new createNewCHat().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,ScrollingActivity.ServerLocation + "/alterChat.php", Data).get();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
    Intent intent = new Intent(getApplicationContext(), ScrollingActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    intent.putExtra("EXIT", true);
    startActivity(intent);
}

@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
    if(position != 0 && !cBoxPrivateChat.isChecked()) {
        members = members + "#" + number.get(position) + "#";
        TextView MemberText = new TextView(this);
        MemberText.setId(2000000 + position);
        MemberText.setText(phoneNameNumber[position][0] + " " + phoneNameNumber[position][1]);
        LinearLayout memberLayout = (LinearLayout) findViewById(R.id.membersLayout);
        RadioGroup.LayoutParams params = new RadioGroup.LayoutParams(RadioGroup.LayoutParams.MATCH_PARENT, 100);
        memberLayout.addView(MemberText, params);
        MemberText.setOnClickListener(this);
        memberCount++;
        if(memberCount > 1){
            cBoxPrivateChat.setEnabled(false);
            cBoxPrivateChat.setChecked(false);
        }
    } else if(position != 0 && cBoxPrivateChat.isChecked() && members.equals("")){
        members = members + "#" + number.get(position) + "#";
        TextView MemberText = new TextView(this);
        MemberText.setId(2000000 + position);
        MemberText.setText(phoneNameNumber[position][0] + " " + phoneNameNumber[position][1]);
        LinearLayout memberLayout = (LinearLayout) findViewById(R.id.membersLayout);
        RadioGroup.LayoutParams params = new RadioGroup.LayoutParams(RadioGroup.LayoutParams.MATCH_PARENT, 100);
        memberLayout.addView(MemberText, params);
        MemberText.setOnClickListener(this);
        memberCount++;
    }
}

@Override
public void onNothingSelected(AdapterView<?> parent) {

}


public void loadAllContacts(){
    nameList = new ArrayList<String>();
    number = new ArrayList<String>();
    ContentResolver cr = getContentResolver();
    Cursor cursor = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PROJECTION, null, null, null);
    if (cursor != null) {
        try {
            final int nameIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
            final int numberIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);


            nameList.add(0,"Select chat members");
            number.add(0,"");

            while (cursor.moveToNext()) {
                if(!cursor.getString(nameIndex).equals(lastContactName)){
                    nameList.add(cursor.getString(nameIndex));
                    number.add(cursor.getString(numberIndex));
                    lastContactName = cursor.getString(nameIndex);
                }
            }
        } finally {
            cursor.close();

        }
        phoneNameNumber = new String[nameList.size()][2];

        for(int i = 0; i<nameList.size();i++){
            phoneNameNumber[i][0] = nameList.get(i);
            phoneNameNumber[i][1] = number.get(i);
        }

        Arrays.sort(phoneNameNumber, new Comparator<String[]>() {
            @Override
            public int compare(final String[] entry1, final String[] entry2) {
                final String time1 = entry1[0];
                final String time2 = entry2[0];
                return time1.compareTo(time2);
            }
        });

    }

}
}

哦,顺便说一下有人知道为什么数组中有重复项?因为如果我只是在微调器上使用列表名称我没有任何重复

2 个答案:

答案 0 :(得分:1)

所以你可能想要这样的功能:

(但我没有理解你的#34;我需要知道重复的地方是什么&#34; ...为什么?而且你的代码也没有以任何方式使用其他维度,只是[0]被比较......所以我在我的代码中也模仿它,但也许它不是你想要的?)

import java.util.Arrays;  // Maybe all of your problem is that you had typo in import?
// This is language standard stuff, available everywhere IMHO

    /**
     * Removes duplicates and nulls from sorted array, first item (sortedArray[i][0]) is considered
     * for duplicates search, rest of values sortedArray[i][1..n] is not considered at all.
     * 
     * @param sortedArray
     *            sorted 2D String array, can have any 1 <= length in second dimension.
     * @return items with duplicate in [i][0] or null will be removed from result array.
     */
    public static String[][] removeDuplicateOrNullItems(final String[][] sortedArray) {
        // validate input
        if (null == sortedArray || sortedArray.length <= 1) {
            return sortedArray; // garbage in, garbage out
        }
        // search for first duplicate (if any)
        int i = 0;
        while (++i < sortedArray.length) {
            if (null == sortedArray[i][0] || sortedArray[i][0].equals(sortedArray[i - 1][0])) {
                break;
            }
        }
        if (i == sortedArray.length) {
            return sortedArray; // no duplicate found, return input
        }
        // First duplicate is at index i, now compact the rest of array content (overwriting dupes)
        int newi = i; // will serve both as count of unique values, and compact-writing index
        while (++i < sortedArray.length) {
            if (null == sortedArray[i][0] || sortedArray[i][0].equals(sortedArray[i - 1][0])) {
                continue; // another duplicate, skip this one
            }
            sortedArray[newi++] = sortedArray[i]; // valid value, compact it
        }
        return Arrays.copyOf(sortedArray, newi); // return the compacted result
    }

// demo how to call it:

        String[][] in = {{"A1", "A2"}, {"A1", "dupA"}, {null, null}, {"B1", "B2"}, {"B1", "dupB1"}, {"B1", "dupB2"}, {"C1", "C2"}};
//      String[][] in = {{"A1", "A2", "A3"}, {"B1", "B2", "B3"}};
//      String[][] in = null;

        String[][] out = removeDuplicateOrNullItems(in);

我试着对它做一些评论,让你知道它在做什么......尽管使用调试器并逐行逐步踩几下可能会有很多帮助。

如果你真的想避免使用java.util.Arrays,那么最后的return Arrays.copyOf...应该替换为:

    final String[][] result = new String[newi][sortedArray[0].length];
    for (i = 0; i < newi; ++i) result[i] = sortedArray[i];
    return result;

加入:
关于这3个任务:

        phoneNameNumber = null;
        phoneNameNumber = new String[tmp.length][2];
        phoneNameNumber = tmp;

我不知道你对编程的了解,所以这可能很难。

phoneNameNumberString[][]类型,它是放置在内存中的地址(指针),存储数组(维数不是重要的ATM)。

首先将它设置为null,然后设置为新的已分配空间,最后设置为tmp已指向的空间(与tmp共享相同的数组)。分配新内存的第二行是无用的,它将被第三行直接覆盖,新分配的内存将用于GC(垃圾收集器)。

如果要将值从tmp复制到内存中新分配的区域(真实副本),则可以执行for循环,并分配phoneNameNumber[i][j] = tmp[i][j];。然后,这将与tmp只共享指向String本身的指针,这在Java中是可以的,因为String是不可变的(不能更改值,所以如果你保留地址一个字符串,你可以确定它的内容没有改变,即使代码的其他部分正在使用该指针)。

如果你只做phoneNameNumber[i] = tmp[i];复制它,它会在第一眼看到相同的内容(新phoneNameNumber中的值与tmp中的值相同。但是&#39}。差异,现在phoneNameNumbertmp也会共享两个String内部微小数组。所以在复制之后,如果你做tmp[0][1] = null;phoneNameNumber[0][1]会突然包含null也是(因为存储那些指向Strings的指针的内存区域是共享的,所以你在那里为这两个变量编写空指针)。

或复制(真实副本)数组使用java.util.Arrays.copy***方法。

将其设置为null的第一行实际上有时在Java程序中使用,将GC的某些内存标记为&#34;要发布&#34;如果您知道不会使用它更多。

当您用另一个指针立即覆盖phoneNameNumber时,这是没用的,如果您只是直接将tmp分配给它,GC也将收集原始内存(丢失旧值= ready对于GC)。实际上在这种情况下表现明智的是,将旧值归零的中间步骤会损害JVM + GC,因为它解决了两个赋值而不是一个,结果将是相同的。

正如您所看到的,我并不关心我是否使用较简单的方法复制或共享原始数组的部分内容。因此,该方法的编写方式将修改原始输入。如果你想保持它完整(并在不同的数组中接收结果),你必须用输入数组的副本调用它,让它搞乱副本:
String[][] out = removeDuplicateOrNullItems(Arrays.copyOf(in, in.length));
编辑: BUG ^^此copyOf或in.clone()不是深拷贝,创建副本 在所有维度级别上,但只创建上层数组的副本,共享下面的所有内容。

代码示例:

// INIT

String[][] in = {{"A1", "A2"}, {"B1", "B2"}};
// in is array of 2 references (pointers) at String[] value.
// Let's say in@adr1 = [@r1, @r2] (at address @adr1 in memory)
// @r1 = array of two references to Strings [@"A1", @"A2"], @r2 = [@"B1", @"B2"]
String[][] inCopy = in.clone();
// inCopy has copy of top level array (content of in@adr1) at address @adr2
// inCopy@adr2 = [@r1, @r2];  so this is in new memory,
// but the values are old @r1 and @r2, sharing the second level arrays with "in"

// modification CASE 1

String[] x = {"X1", "X2"};  // x@adr3 = [@"X1", @"X2"]
in[0] = x;
// in@adr1 = [x@adr3, @r2], so in = [[X1, X2], [B1, B2]]
// inCopy@adr2 = [@r1, @r2], so inCopy = [[A1, A2], [B1, B2]]

// modification CASE 2 (on deeper level, where clone/copyOf didn't create copy)

in[1][0] = "X";  // @r2[0] modified to contain @"X";
// in@adr1 = [x@adr3, @r2], @r2 = [@"X", @"B2"],  in = [[X1, X2], [X, B2]]
// inCopy@adr2 = [@r1, @r2] (same @r2!), so inCopy = [[A1, A2], [X, B2]]

如您所见,在第二种情况下,通过修改[1] [0]来修改inCopy。为防止这种情况,您必须按深度复制多维数组:

String[][] in = {{"A1", "A2"}, {"B1", "B2"}};
String[][] inCopy = new String[in.length][in[0].length];
// inner arrays of inCopy are cloned to new memory, not shared with "in"
for (int i = 0; i < in.length; ++i) {
    inCopy[i] = in[i].clone();
}

但是你可以把它作为警告,在你的假设中造成重大错误并不困难。 :/总是测试你的代码......:D(单元测试的自动测试非常适合这种情况)。在编写了第一个好的版本之后,一步一步地在调试器中逐步完成它只是为了验证它是否按预期工作(加上它有助于学习很多)。

通常,当您创建自己的方法时,最好将输入作为不可变值进行操作,而不是修改它们(在理想情况下,我的方法会在最开始时创建数组的副本)它)。这会导致更少的惊喜错误,当您调用API时,它会将修改后的数组作为新副本返回,但不会修改输入的数据。 (当我要求为UI存储一些值时,Java的类Date非常出色地抓住我,并用它做一些计算,看看例如日期是否会在14天后到期,然后我想知道为什么UI中的值确实发生了变化(因为我对原始内存进行了计算,而不是复制它)。String是不可变的,所以每当你将字符串更改为某个新值时,你可以打赌你确实收到了新的指针,如果其他代码直接持有旧代码,它仍然会看到旧的字符串。=对程序员不断匆忙而言不那么令人惊讶。

嗯......这太长了。如果你没有弄清楚我在说什么,试着搜索计算机内存的工作原理,内存分配是什么,然后在Java中,如何存储变量found something here, looks like free lecture notes from uni course。如果你不熟悉编程,一开始可能会让人感到困惑,但是后来搜索一些描述计算机工作原理的孩子书籍,或者一些关于编程的早期书籍(1970-1990时代),它们应该为你提供很好的基础来理解什么是发生在内部,当你将阅读有关JVM的更多内容时。

答案 1 :(得分:0)

Java是一种功能强大的语言,因为它有很多有用的库。我建议你使用ArrayList,因为它会提高你的效率,性能和复杂性。

如果你想在不使用这些库的情况下解决这类问题,这是我能想到的最好的。

// I don't know what's your phoneNameNumber, but I assume it is 2D string array:
String[][] phoneNameNumber = new String[][];
String duplicatedIndicesString = "";

// Loop through phoneNameNumber
for (int i=0; i<phoneNameNumber.length; i++) {
    // Find duplicates
    for (int i2=0; i<phoneNameNumber.length; i2++) {
        boolean duplicated = true;

        for (int j=0; j<phoneNameNumber[i2].length; j++) {
            if (phoneNameNumber[i][j].equals(phoneNameNumber[i2].j) == false) {
                // Not duplicate for this i2
                duplicated = false;
                break;
            }
        }

        if(duplicated == true) {
            duplicatedIndicesString += i2;
            if (i2!=phoneNameNumber.length-1) {
                // Store duplicated index for later dynamic allocation..
                duplicatedIndicesString += ",";
            }
        }
    }
}

// Now let's copy results to a new array.
String[] duplicatedIndicesStringArray = duplicatedIndicesString.split(",");
String[][] resultPhoneNameNumber = new String[phoneNameNumber.length - dupicatedIndices.length][2];
int resultIndex = 0;

for (int i=0; i<phoneNameNumber.length; i++) {
    boolean duplicated = false;

    for (j=0; j<duplicatedIndicesStringArray.length; j++) {
        if (Integer.parseInt(duplicatedIndicesStringArray[j]) == i) {
            duplicated = true;
            break;
        }
    }

    if (duplicated == false) {
        resultPhoneNameNumber[resultIndex] = phoneNameNumber[i];
        resultIndex++;
    }
}

这可能是我写了一段时间以来最丑陋的代码。我这样做是因为我早上喝了太多咖啡。在编码之前先想想。