查找数组中最低唯一值的索引

时间:2015-03-02 13:20:02

标签: c# arrays

我试图找到输入字符串中最低唯一值的索引,数字范围是1到9。

我有两个问题:

  • 与使用for的循环相比,是否有更好的循环方式?我不包括数组的最后一个元素,因为它会引发异常,因为我检查了下一个元素的值。我知道如果我包含一个if语句来检查它是否是最后一个元素但是它将检查每次迭代不是最优的,那么我可以这样做,因此我在循环之外进行。< / p>

  • 有没有更好的方法可以用来查找结果?

我愿意接受任何评论。

        string line = "3 3 9 1 6 5 1 5 3 6";

        // 1 array to be sorted in order to find the lowest unique value more easily
        // another array so I can get the index of the lowest unique value since 
        // the first array is going to be sorted
        int[] input = Array.ConvertAll(line.Split(' '), int.Parse);
        int[] input2 = Array.ConvertAll(line.Split(' '), int.Parse);
        Array.Sort(input);

        int? previous = null;
        int lowest = 0;

        for (int i = 0; i < input.Length - 1; i++)
        {
            if (input[i] != previous && input[i] < input[i + 1])
            {
                lowest = input[i];
                break;
            }
            previous = input[i];
        }

        int last = input[input.Length - 1];
        if (last != previous && lowest == 0)
        {
            lowest = last;
        }

        Console.WriteLine(Array.IndexOf(input2, lowest));

8 个答案:

答案 0 :(得分:4)

您可以使用LINQ并对元素进行分组以获取计数(唯一性)。然后找到最低值。

int lowest = input.GroupBy(x => x, (k,v) => new { Key = k, Values = v }) /*group elements*/
                  .Where(x => x.Values.Count() == 1) /*get unique ones*/
                  .Min(x => x.Key) /*get the lowest*/
             ;

使用此数组,它会按预期返回2

int[] input = new int[] {1, 1, 2, 3, 4};

答案 1 :(得分:1)

你的方法的瓶颈是排序,而不是搜索排序的结果,因为sort通常是快速排序(O(n2) - 最坏的情况,但你很可能达到平均复杂度O(n log) n))和搜索是O(n)。

你试图解决的问题不需要排序,你可以通过循环遍历值和计数(如count-sort)来复合O(n)。

答案 2 :(得分:1)

假设您有一个MinBy LINQ运算符(Interactive Extensions提供了一个,但快速版本如下)并且愿意添加一个类型 为了提供IEqualityComparer<T>实现,由于LINQ的延迟操作以及将当前索引传递给委托的Select的重载,它可以一次完成:

var idx = input.Split(' ').Select((c, idx) => new IndexedObject(c, idx) })
                          .Distinct()
                          .MinBy(x => x.Value)
                          .Index;

其中

class IndexedObject<TValue> : IEqualityComparer<TValue> {
  public TValue Value { get; private set; } 
  public int Index { get; private set; }

  public IndexedObject(TValue value, int index) {
    Value = value;
    Index = index;
  }
  // Forward  IEqualityComparer<TValue> to Value
}

帮助,快速,无错误检查,版本:

public static class EnumerableEx {
  public static TObject MinBy<TObj, TProp>(
                            IEnumerable<TObject> input,
                            Func<TObject, TProp> selector) {
    if (!input.MoveNext()) { return default(TObject); }

    TObject obj = input.Current;
    TProp theProp = selector(obj);

    while (input.MoveNext()) {
      var newObj = input.Current;
      var newProp = selector(newObj):
      if (newProp < theProp) {
        obj = newObj;
        theProp = newProp;
      }
    }
    return obj;
}

答案 3 :(得分:0)

对于大型数组,您应该使用SortedSet

由于您访问i + 1处的元素,因此您应该先停止循环:

for (int i = 0; i < input.Length - 2; i++) ...

答案 4 :(得分:0)

试试这个

int[] input = Array.ConvertAll(line.Split(' '), int.Parse);
int[] input2 = Array.ConvertAll(line.Split(' '), int.Parse);
var tempIndex = input.Distinct().OrderByDescending(a=>a).Select(a => input2.ToList().IndexOf(a)).FirstOrDefault();

    Console.WriteLine(tempIndex);

这是调试结果

  

2

答案 5 :(得分:0)

您应该为每个数字存储两个值:

  1. 这个数字的计数;
  2. 找到的第一个数字的索引。
  3. 然后,您可以检测count等于1的最小元素,并获取此元素的index

    var line = "3 6 9 ... 9 0";
    var input = Array.ConvertAll(line.Split(' '), int.Parse);
    var digits = new Tuple<int, int>[10];
    
    for (int i = 0; i < digits.Length; i++)
        digits[i].Second = -1;
    
    for (int i = 0; i < input.Lenght; i++)
    {
        digits[input[i]].First++;
    
        if (digits[input[i]].Second == -1)
            digits[input[i]].Second = i;
    }
    
    int result = -1;
    for (int i = 0; i < digits.Length; i++)
    {
        if (digits[i].First == 1)
        {
            result = digits[i].Second;
            break;
        }
    }
    

    此解决方案为您提供O(N)时间复杂度。

答案 6 :(得分:0)

此函数返回int数组中较低值的索引:

int[] anArray= new int[] { 5, 40, 34, 5, 1, 2, 3, 4 };
int lowerIndex = getLowerIndex(anArray);

private int getLowerIndex(int[] input)
{
    //create temp array
    int[] sortTab = new int[input.Length];
    //copy array
    for (int i = 0; i < input.Count(); i++)
    {
        sortTab[i] = input[i];
    }
    //copy array
    Array.Sort(sortTab);
    //get lower value 
    int lowerValue = sortTab[0];
    //get index of lower value
    int lowerIndex = Array.IndexOf(input, lowerValue);
    return lowerIndex;
}

答案 7 :(得分:0)

您可以使用SortedDictionary将最小值保存为键,将索引保存为值。它只在列表中循环一次。

string line = "3 3 9 1 6 5 1 5 3 6";
int[] input = Array.ConvertAll(line.Split(' '), int.Parse);
List<int> unique_values = new List<int>();
SortedDictionary<int, int> lowest_unique_values = new SortedDictionary<int, int>();

for (int i = 0; i < input.Length; i++)
{
   if (!unique_values.Contains(input[i]))
   {
      unique_values.Add(input[i]);
      lowest_unique_values.Add(input[i], i);
   }
   else
   {
      lowest_unique_values.Remove(input[i]);
   }
}

if (lowest_unique_values.Count > 0)
{
   // index of smallest unique value
   KeyValuePair<int, int> smallest_value_and_index = lowest_unique_values.First();
   Console.WriteLine(smallest_value_and_index.Key + " " + smallest_value_and_index.Value);
}

生成的字典还将包含所有唯一值(从最小到最大排序)及其在列表中的相应索引。第一个值是您想要的值。