【问题标题】:Getting the absolute position from relative index [^x] in array, list or dictionary? (C#)从数组、列表或字典中的相对索引 [^x] 获取绝对位置? (C#)
【发布时间】:2021-01-22 04:32:08
【问题描述】:

从C#版本8开始,有了indexing的新方式,如示例所示:

void Main()
{
    Index idx = ^5; // counted from last to first element

    var sentence = new string[]
    {
        "The", "quick", "brown", "fox",         // position 0 ... 3
        "jumped", "over", "the", "lazy", "dog"  // position 4 ... 8
    };
    var lstSentence = sentence.ToList(); // applicable to list as well

    Console.WriteLine(sentence[idx]);
    Console.WriteLine(lstSentence[idx]);
}

它返回jumped

到目前为止一切顺利。但是如何有效地获得代表^5 的绝对位置呢?
我看到 .NET 内部使用的是Index(我在这个例子中添加了它),并且有一个 value 属性。

如何获得sentence[^5] 的位置? 类似的东西

var absPos = sentence[^5].Index.Value; // get absolute position (which is = 4)

(但不幸的是,这似乎不存在)

我知道有一个公式(元素数 - 右起位置),但编译器/.net 会计算并可能将其存储在某处。

更新: idx.Value 不是解决方案,它只是将相对值 5 与 .IsFromEnd 一起存储,这是真的。但是你不能直接访问它,就像我想知道的sentence[^5].Index.Value

注意:这对Dictionary 也很有用,如果您查看RudimentaryMultiValuedDictionary Example - 如果您想添加一个额外的索引器,如public List<TValue> this[Index idx],您将需要它。你需要的internalDictionary.ElementAtOrDefault(i) 仅适用于整数值(绝对位置)。

【问题讨论】:

  • ^0 等于 sentence.Length 所以你的索引应该是 sentence.Length - 5 docs.microsoft.com/en-us/dotnet/csharp/whats-new/…
  • 绝对位置是什么意思?
  • 不,这是不可能的。没有语言功能可以告诉您这一点。 ^5 构造的字面意思是“从末尾返回 5”,索引是在数组索引期间评估的,您返回的是该索引处数组中插槽的内容,而不是知道它在数组中的位置的东西.您必须创建一个方法来模仿评估 ^5 并为您返回索引的代码。
  • @Emanuele - 数组项的索引 - 在示例中为值 4。
  • @Matt 对您的最新评论的回答是否定的。它不被存储。 Index.GetOffset 是您想要的方法。 (^5).GetOffset(sentence.Length) 会告诉你sentence 的索引。

标签: c# arrays .net list dictionary


【解决方案1】:

如果您使用反编译器查看为您的示例生成了什么代码,它看起来像这样:

private static void Main()
{
    Index index = new Index(5, true);
    string[] strArray = new string[] { "The", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog" };
    Console.WriteLine(strArray[index.GetOffset((int)strArray.Length)]);
}

如您所见,它只是使用index.GetOffset((int)strArray1.Length) 来计算偏移量。除了以同样的方式做之外,你自己没有办法做到这一点。没有其他语言结构可供您使用。

(我不确定为什么它将strArray1.Length 属性转换为int,因为它已经是int。)

另请注意,如果您使用以下代码将索引内联:

var sentence = new string[]
{
    "The", "quick", "brown", "fox",
    "jumped", "over", "the", "lazy", "dog"
};

Console.WriteLine(sentence[^5]);

编译成:

string[] strArray = new string[] { "The", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog" };
Console.WriteLine(strArray[(int)strArray.Length - 5]);

这完全优化了 Index 对象的使用。


正如我在下面的 cmets 中提到的,您可以编写一个接受 IList 的扩展方法。然后,这将适用于实现IList 的任何东西,例如List<T>、数组、ImmutableSortedSet<T> 等等。

例如:

public static class IndexExt
{
    public static int AbsIndexFor(this IList self, Index index)
    {
        return index.GetOffset(self.Count);
    }
}

那么你可以这样做:

var array = new string[]
{
    "The", "quick", "brown", "fox",
    "jumped", "over", "the", "lazy", "dog"
};

Console.WriteLine(array.AbsIndexFor(^5));

var list = new List<string>
{
    "The", "quick", "brown", "fox",
    "jumped", "over", "the", "lazy", "dog"
};

Console.WriteLine(list.AbsIndexFor(^5));

【讨论】:

  • 转换为int 可能只是作为“防御性编程”生成的代码的一部分,因为在这种情况下 JITter 无论如何都会忽略转换。
  • 谢谢,这解释得很好。所以没有办法,只能使用索引变量,也许可以编写一个帮助扩展方法,允许说strArray.GetAbsIndex(index):类似public static int GetAbsIndex(this string[] strArray, Index index) =&gt; index.GetOffset((int)strArray.Length);
  • 上述扩展方法的通用版本(适用于所有类型的数组):public static int GetAbsIndex&lt;T&gt;(this T[] strArray, Index index) =&gt; index.GetOffset((int)strArray.Length);
  • @Matt 你不需要 - IList.Count 映射到 .Length。看看我更新的答案——你只需要使用IList 来支持普通数组和List&lt;T&gt;。解释见这里:stackoverflow.com/questions/11163297/…
  • 注: - 我最近在 RudimentaryMultiValuedDictionary 中使用了它,这是 Microsoft 的一个示例,您可以找到 here - 我添加了 public int GetAbsIndex(Index index) =&gt; index.GetOffset(internalDictionary.Count()); 因为我想有一个带有 Index idx 参数的附加索引器:internalDictionary.ElementAtOrDefault(i) 需要一个绝对位置。很有用!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-29
  • 1970-01-01
  • 2019-09-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多