C#使用前两个项填充第三个数组。抛弃重复

时间:2015-08-20 19:17:02

标签: c# arrays

寻找一些帮助来解决这个问题。我有两个名字阵列。我需要做的是对它们进行冒泡排序(我已经完成了,请参见下面的代码),并使用前两个数组中的值填充第三个数组,省略重复项,而不是排序第三个数组。下面是我的示例代码,它完全适用于我正在做的事情,除了我需要使用循环来填充第三个数组(逻辑练习)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MergeArray
{
class Program
{
    static void Main(string[] args)
    {
        string[] names1 = { "Bob", "John", "Bill", "Sandy", "Betty", "Bart", "Patty" };
        string[] names2 = { "Andy", "Chris", "Bill", "Walter" };
        string[] names3 = new string[names1.Length + names2.Length];

        string temp;

        foreach (string i in names1)
        {
            for (int j = 0; j < names1.Length - 1; j++)
            {
                if (String.Compare(names1[j], names1[j+1]) > 0)
                {
                    temp = names1[j];
                    names1[j] = names1[j + 1];
                    names1[j + 1] = temp;
                }
            }
        }
        foreach (string i in names2)
        {
            for (int j = 0; j < names2.Length - 1; j++)
            {
                if (String.Compare(names2[j], names2[j + 1]) > 0)
                {
                    temp = names2[j];
                    names2[j] = names2[j + 1];
                    names2[j + 1] = temp;
                }
            }
        }

        names1.CopyTo(names3, 0);
        names2.CopyTo(names3, names1.Length);

        Console.WriteLine(String.Join(Environment.NewLine, names3.Distinct().ToArray()));
            Console.ReadLine();

    }
}
}

最后,这段代码完成了我需要做的事情,第三个阵列填充了“Bart,Betty,Bill,Bob,John,Patty,Sandy,Andy,Chris,Walter”。它没有填写重复的“Bill”,它只是将两个数组加在一起,而不是排序第三个(这是我需要做的)。我需要帮助的是将我填充第三个数组的部分转换为循环而不是:

        names1.CopyTo(names3, 0);
        names2.CopyTo(names3, names1.Length);

        Console.WriteLine(String.Join(Environment.NewLine, names3.Distinct().ToArray()));

请帮助我了解我需要在这里做些什么。

7 个答案:

答案 0 :(得分:1)

linq的力量!

string[] names1 = { "Bob", "John", "Bill", "Sandy", "Betty", "Bart", "Patty" };
string[] names2 = { "Andy", "Chris", "Bill", "Walter" };

string[] names3 = names1.Union(names2).Distinct().ToArray();

答案 1 :(得分:1)

正如ryanyuyu建议的那样,使用修改后的合并操作 这将在您对它们进行排序后进行。

int m = 0;
int n = 0;
while ((m < names1.Count) && (n < names1.Count))
{
    int comparison = String.Compare(names1[m], names2[n]);
    if (comparison < 0) // names1[m] is before names2[n]
    {
        names3.Add(names1[m]);
        m = m + 1;
    }
    else if (comparison > 1) //names2[n] is before names1[m]
    {
        names3.Add(names2[n]);
        n = n + 1;
    }
    else //names1[m] is equal to names2[n], only add one.
    {
        names3.Add(names1[m]);
        m = m + 1;
        n = n + 1;
    }
}
//either names1 or names2 ran out of entries. fill names3 with whatever is left
while (m < names1.Count)
{
    names3.Add(names1[m]);
    m = m + 1;
}
while (n < names2.Count)
{
    names3.Add(names2[n]);
    n = n + 1;
}

如果原始数组本身可能包含重复项,则可以使用HashSet跟踪已添加的值。

List<string> names1 = new List<string>();
List<string> names2 = new List<string>();
List<string> names3 = new List<string>();
var included = new HashSet<string>();
int m = 0;
int n = 0;
while ((m < names1.Count) && (n < names1.Count))
{
    int comparison = String.Compare(names1[m], names2[n]);
    if (comparison < 0)
    {
        if(included.Add(names1[m]))
        {
            names3.Add(names1[m]);
        }
        m = m + 1;
    }
    else if (comparison > 1)
    {
        if (included.Add(names2[n]))
        {
            names3.Add(names2[n]);    
        }
        n = n + 1;
    }
    else
    {
        names3.Add(names1[m]);
        m = m + 1;
        n = n + 1;
    }
}
while (m < names1.Count)
{
    if (included.Add(names1[m]))
    {
        names3.Add(names1[m]);
    }
    m = m + 1;
}
while (n < names2.Count)
{
    if (included.Add(names2[n]))
    {
        names3.Add(names2[n]);
    }
    n = n + 1;
}

当然,此时您也可以将names3设为HashSet并跳过额外的检查。保持included分开的唯一好处是names3保留了排序顺序。如果names3本身是HashSet并且你在最后做了names3.ToArray(),则无法保证这是真的。

答案 2 :(得分:1)

假设您的冒泡排序成功对元素进行排序,您可以使用修改后的合并操作将最终数组放在一起。基本上,合并需要两个排序的数组,并通过比较每个数组的“顶部”元素并将其移动到复合数组来将它们放在一起。

在执行此操作时,您只需要检查重复项。并且由于您的数组都已排序,所有重复项将聚合成组,因此您只需要跟踪最近的重复项。

这样的事情(非常详细且评论很多)可以起作用:

public static string[] MergeNoDuplicates(string[] left, string[] right)
{
    var mergedArray = new string[left.Length + right.Length];

    //since the arrays are sorted, we only need to keep track of the most recent duplicate
    string duplicateChecker = null; 

    int mergeIndex = 0; 
    int l = 0; //index for left array
    int r = 0; //index for right array
    //while there are more element in at least one of the two arrays
    bool leftHasElements = l < left.Length;
    bool rightHasElements = r < right.Length;
    while (leftHasElements && rightHasElements)
    {
        string leftString = left[l];
        string rightString = right[r];
        int comparisonResult = leftString.CompareTo(rightString);
        if (comparisonResult < 0) //left string comes before right string
        {
            //not a duplicate
            if (leftString.CompareTo(duplicateChecker) != 0)
            {
                mergedArray[mergeIndex] = leftString;
                mergeIndex++;
                duplicateChecker = leftString;
            }
            //regardless of whether it's a duplicate move onto the next element
            l++;
        }
        else if (comparisonResult > 0) //right string comes before left
        {
            if (rightString.CompareTo(duplicateChecker) != 0)
            {
                mergedArray[mergeIndex] = rightString;
                mergeIndex++;
                duplicateChecker = rightString;
            }

            r++;
        }
        else //comparisonResult by default == 0
        {
            //since they are the same string, just insert one (if needed), but increment both arrays
            if (leftString.CompareTo(duplicateChecker) != 0)
            {
                mergedArray[mergeIndex] = leftString;
                mergeIndex++;
                duplicateChecker = leftString;
            }

            l++;
            r++;
        }

        leftHasElements = l < left.Length;
        rightHasElements = r < right.Length;
    }

    //now at least one of the arrays is empty, so add all of the remaining
    //non-duplicate elements of the other to the array
    //if either is false, the loop won't execute in the first place
    while (leftHasElements)
    {
        string leftString = left[l];
        if (leftString.CompareTo(duplicateChecker) != 0)
        {
            mergedArray[mergeIndex] = leftString;
            mergeIndex++;
            duplicateChecker = leftString;
        }

        l++;
        leftHasElements = l < left.Length;
    }

    while (rightHasElements)
    {
        string rightString = right[r];
        if (rightString.CompareTo(duplicateChecker) != 0)
        {
            mergedArray[mergeIndex] = rightString;
            mergeIndex++;
            duplicateChecker = rightString;
        }

        r++;
        rightHasElements = r < right.Length;
    }

    //now remove null elements (if needed) and return
    //alternatively, just use LINQ's TakeWhile and ToArray
    if (mergeIndex == mergedArray.Length)
        return mergedArray;
    var returnedArray = new string[mergeIndex];
    Array.Copy(mergedArray, returnedArray, mergeIndex);
    return returnedArray;
}

Demo

答案 3 :(得分:0)

我建议使用&#34;区别&#34;

复制到列表&lt;&gt;

使用&#34; AddRange()&#34;添加第二个数组。

使用&#34; Distinct()&#34;消除重复,

最后,将列表转换回数组。

实施例

List<string> myList = myArray.Cast<string>().ToList();
myList.AddRange(mySecondArray);
string[] myNewArray = myList.Distinct().toArray();

答案 4 :(得分:0)

为什么不:

List<string> names = new List<string>();
names.AddRange(names1);
names.AddRange(names2);
names.Sort();
string[] names3 = names.Distinct().ToArray();

答案 5 :(得分:0)

你可以使用.Union:

string[] names1 = { "Bob", "John", "Bill", "Sandy", "Betty", "Bart", "Patty" };
string[] names2 = { "Andy", "Chris", "Bill", "Walter" };

string[] names3 = names1.Union(names2).ToArray();

答案 6 :(得分:0)

我会使用这样的循环:

int names1I = 0;
int names2I = 0;

for(int i = 0; names1I < names1.Length && names2I < names2.Length; i++)
{
    while(names1I < names1.Length && names3.Contains(names1[names1I]))
      names1I++;
    while(names2I < names2.Length && names3.Contains(names2[names2I]))
      names2I++;

    if(names1I == names1.Length) //if you have already reached the end of array 1, you have to use array 2
      names3[i] = names2[names2I++];
    else if(names2I == names2.Length) //if you have already reached the end of array 2, you have to use array 1
      names3[i] = names1[names1I++];
    else //else take the smaller of the 2 possible values
      names3[i] = (names1[names1I] <= names2[names2I]) ? names1[names1I++] : names2[names2I++];
}