我的情况是我想要仅列出另一个列表的列表。如果可能的话,参考。
到目前为止我所做的是这里:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
char (*points)[50];
points = malloc(sizeof(*points) * 2);
if (points == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
fp = fopen("/Users/shubhamsharma/Desktop/data.txt", "r");
if (fp == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
fgets(points[0], sizeof(*points), fp);
fgets(points[1], sizeof(*points), fp);
fclose(fp);
printf("%s", points[0]);
printf("%s", points[1]);
free(points);
return 0;
}
示例:包含6个元素的列表,从2开始,结束为4。
List<string> partialList = originalList.Skip(start).Take(end-start).ToList();
据我所知.ToList()它会创建原始结果的副本。因此,这将是价值而非参考。所以我的问题是:是否有任何“按参考”的方式来实现我想要的结果?
答案 0 :(得分:15)
您可以轻松编写自己的切片类:
public class ReadOnlyListSlice<T> : IReadOnlyList<T>
{
private readonly IReadOnlyList<T> _list;
private readonly int _start;
private readonly int _exclusiveEnd;
public ReadOnlyListSlice(IReadOnlyList<T> list, int start, int exclusiveEnd)
{
_list = list;
_start = start;
_exclusiveEnd = exclusiveEnd;
}
public IEnumerator<T> GetEnumerator()
{
for (int i = _start; i <= _exclusiveEnd; ++i)
yield return _list[i];
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count
{
get { return _exclusiveEnd - _start; }
}
public T this[int index]
{
get { return _list[index+_start]; }
}
}
用法:
List<int> ints = Enumerable.Range(1, 10).ToList();
var test = new ReadOnlyListSlice<int>(ints, 4, 7);
foreach (var i in test)
Console.WriteLine(i); // 5, 6, 7, 8
Console.WriteLine();
for (int i = 1; i < 3; ++i)
Console.WriteLine(test[i]); // 6, 7
您也可以编写可写版本,但如果您实现IList<T>
,您最终将不得不实施许多您可能不需要使用的方法。< / p>
但是,如果您不介意只执行IReadOnlyList<T>
(并暗示IEnumerable<T>
),那就不那么难了:
public class ListSlice<T> : IReadOnlyList<T>
{
private readonly List<T> _list;
private readonly int _start;
private readonly int _exclusiveEnd;
public ListSlice(List<T> list, int start, int exclusiveEnd)
{
_list = list;
_start = start;
_exclusiveEnd = exclusiveEnd;
}
public IEnumerator<T> GetEnumerator()
{
for (int i = _start; i <= _exclusiveEnd; ++i)
yield return _list[i];
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count
{
get { return _exclusiveEnd - _start; }
}
public T this[int index]
{
get { return _list[index+_start]; }
set { _list[index+_start] = value; }
}
}
使用:
List<int> ints = Enumerable.Range(1, 10).ToList();
var test = new ListSlice<int>(ints, 4, 7);
foreach (var i in test)
Console.WriteLine(i); // 5, 6, 7, 8
Console.WriteLine();
test[2] = -1;
for (int i = 1; i < 4; ++i)
Console.WriteLine(test[i]); // 6, -1, 8
当然,不实施IList<T>
的缺点是您无法将ListSlice<T>
传递给期望IList<T>
的方法。
我将public class ListSlice<T> : IList<T>
的完整实施留给了谚语&#34;感兴趣的读者&#34;。
如果你想实现List<T>.FIndIndex()
的等价物,它也很简单。只需将其添加到任一类:
public int FindIndex(int startIndex, int count, Predicate<T> match)
{
for (int i = startIndex; i < startIndex + count; ++i)
if (match(this[i]))
return i;
return -1;
}
这是一个完整的可编辑控制台应用程序:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
public class ReadOnlyListSlice<T> : IReadOnlyList<T>
{
private readonly IReadOnlyList<T> _list;
private readonly int _start;
private readonly int _exclusiveEnd;
public ReadOnlyListSlice(IReadOnlyList<T> list, int start, int exclusiveEnd)
{
_list = list;
_start = start;
_exclusiveEnd = exclusiveEnd;
}
public IEnumerator<T> GetEnumerator()
{
for (int i = _start; i <= _exclusiveEnd; ++i)
yield return _list[i];
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count
{
get { return _exclusiveEnd - _start; }
}
public T this[int index]
{
get { return _list[index + _start]; }
}
}
public class ListSlice<T> : IReadOnlyList<T>
{
private readonly IList<T> _list;
private readonly int _start;
private readonly int _exclusiveEnd;
public ListSlice(IList<T> list, int start, int exclusiveEnd)
{
_list = list;
_start = start;
_exclusiveEnd = exclusiveEnd;
}
public IEnumerator<T> GetEnumerator()
{
for (int i = _start; i <= _exclusiveEnd; ++i)
yield return _list[i];
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int Count
{
get { return _exclusiveEnd - _start; }
}
public T this[int index]
{
get { return _list[index+_start]; }
set { _list[index+_start] = value; }
}
}
internal class Program
{
private static void Main()
{
var ints = Enumerable.Range(1, 10).ToList();
Console.WriteLine("Readonly Demo\n");
demoReadOnlySlice(ints);
Console.WriteLine("\nWriteable Demo\n");
demoWriteableSlice(ints);
}
private static void demoReadOnlySlice(List<int> ints)
{
var test = new ReadOnlyListSlice<int>(ints, 4, 7);
foreach (var i in test)
Console.WriteLine(i); // 5, 6, 7, 8
Console.WriteLine();
for (int i = 1; i < 4; ++i)
Console.WriteLine(test[i]); // 6, 7, 8
}
private static void demoWriteableSlice(List<int> ints)
{
var test = new ListSlice<int>(ints, 4, 7);
foreach (var i in test)
Console.WriteLine(i); // 5, 6, 7, 8
Console.WriteLine();
test[2] = -1;
for (int i = 1; i < 4; ++i)
Console.WriteLine(test[i]); // 6, -1, 8
}
}
}
答案 1 :(得分:8)
可以使用反射和ArraySegment
类:
var originalList = Enumerable.Range(0, 6).ToList();
var innerArray = (int[])originalList.GetType().GetField("_items", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(originalList);
var partialList = (IList<int>)new ArraySegment<int>(innerArray, 2, 3);
partialList[0] = -99;
partialList[1] = 100;
partialList[2] = 123;
Console.WriteLine(String.Join(", ", originalList));
输出:
0, 1, -99, 100, 123, 5
请注意,这取决于实现细节(_items
类中的私有List<>
字段),因此不能使用未来证明。此外,如果您将一些项添加到原始列表中,这将失败(_items
成员将被新数组替换)。谢谢@IvanStoev提及它。
如果您的原始集合是普通数组,则不会出现问题。
答案 2 :(得分:2)
您可以简单地使用Where
方法将lambda接受项索引作为其第二个参数:
var arr = Enumerable.Range(0, 60);
var subSequence = arr.Where((e, i) => i >= 20 && i <= 27);
foreach (var item in subSequence) Console.Write(item + " ");
输出:20,21,22,23,24,25,26,27