Подтвердить что ты не робот

С# эквивалент вращения списка с использованием операции кусочка python

В python я могу взять список my_list и повернуть содержимое:

>>> my_list = list(range(10))
>>> my_list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> new_list = my_list[1:] + my_list[:1]
>>> new_list
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]

Какой эквивалентный способ в С# создать новый список, состоящий из двух фрагментов существующего списка С#? Я знаю, что при необходимости могу генерировать грубую силу.

4b9b3361

Ответ 1

var newlist = oldlist.Skip(1).Concat(oldlist.Take(1));

Ответ 2

Вы можете легко использовать LINQ для этого:

// Create the list
int[] my_list = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

IEnumerable<int> new_list =
    my_list.Skip(1).Concat(my_list.Take(1));

Вы даже можете добавить это как метод расширения, например:

public static IEnumerable<T> Slice<T>(this IEnumerable<T> e, int count)
{
     // Skip the first number of elements, and then take that same number of
     // elements from the beginning.
     return e.Skip(count).Concat(e.Take(count));
}

Конечно, в вышеупомянутой ситуации должна быть некоторая проверка ошибок, но общая предпосылка.


Подумав об этом, есть определенные улучшения, которые могут быть достигнуты в этом алгоритме, что улучшит производительность.

Вы можете определенно воспользоваться преимуществами, если экземпляр IEnumerable<T> реализует IList<T> или представляет собой массив, используя тот факт, что он проиндексирован.

Кроме того, вы можете сократить количество итераций, необходимых для пропусков и принятия, которые будут взяты внутри тела сообщения.

Например, если у вас есть 200 элементов, и вы хотите срезать со значением 199, то для этого требуется 199 (для начального пропусков) + 1 (для оставшегося элемента) + 199 (для принятия) итераций в тело метода Slice. Это можно сократить, повторяя один раз через список, сохраняя элементы в списке, который затем объединяется в себя (без итерации).

В этом случае компромисс здесь - это память.

С этой целью для метода расширения я предлагаю следующее:

public static IEnumerable<T> Slice<T>(this IEnumerable<T> source, int count)
{
    // If the enumeration is null, throw an exception.
    if (source == null) throw new ArgumentNullException("source");

    // Validate count.
    if (count < 0) throw new ArgumentOutOfRangeException("count", 
        "The count property must be a non-negative number.");

    // Short circuit, if the count is 0, just return the enumeration.
    if (count == 0) return source;

    // Is this an array?  If so, then take advantage of the fact it
    // is index based.
    if (source.GetType().IsArray)
    {
        // Return the array slice.
        return SliceArray((T[]) source, count);
    }

    // Check to see if it is a list.
    if (source is IList<T>)
    {
        // Return the list slice.
        return SliceList ((IList<T>) source);
    }

    // Slice everything else.
    return SliceEverything(source, count);
}

private static IEnumerable<T> SliceArray<T>(T[] arr, int count)
{
     // Error checking has been done, but use diagnostics or code
     // contract checking here.
     Debug.Assert(arr != null);
     Debug.Assert(count > 0);

     // Return from the count to the end of the array.
     for (int index = count; index < arr.Length; index++)
     {
          // Return the items at the end.
          yield return arr[index];
     }

     // Get the items at the beginning.
     for (int index = 0; index < count; index++)
     {
          // Return the items from the beginning.
          yield return arr[index];          
     }
}

private static IEnumerable<T> SliceList<T>(IList<T> list, int count)
{
     // Error checking has been done, but use diagnostics or code
     // contract checking here.
     Debug.Assert(list != null);
     Debug.Assert(count > 0);

     // Return from the count to the end of the list.
     for (int index = count; index < list.Count; index++)
     {
          // Return the items at the end.
          yield return list[index];
     }

     // Get the items at the beginning.
     for (int index = 0; index < list.Count; index++)
     {
          // Return the items from the beginning.
          yield return list[index];          
     }
}

// Helps with storing the sliced items.
internal class SliceHelper<T> : IEnumerable<T>
{
    // Creates a
    internal SliceHelper(IEnumerable<T> source, int count)
    {
        // Test assertions.
        Debug.Assert(source != null);
        Debug.Assert(count > 0);

        // Set up the backing store for the list of items
        // that are skipped.
        skippedItems = new List<T>(count);

        // Set the count and the source.
        this.count = count;
        this.source = source;
    }

    // The source.
    IEnumerable<T> source;

    // The count of items to slice.
    private int count;

    // The list of items that were skipped.
    private IList<T> skippedItems;

    // Expose the accessor for the skipped items.
    public IEnumerable<T> SkippedItems { get { return skippedItems; } }

    // Needed to implement IEnumerable<T>.
    // This is not supported.
    System.Collections.IEnumerator 
        System.Collections.IEnumerable.GetEnumerator()
    {
        throw new InvalidOperationException(
            "This operation is not supported.");
    }

    // Skips the items, but stores what is skipped in a list
    // which has capacity already set.
    public IEnumerator<T> GetEnumerator()
    {
        // The number of skipped items.  Set to the count.
        int skipped = count;

        // Cycle through the items.
        foreach (T item in source)
        {
            // If there are items left, store.
            if (skipped > 0)
            {
                // Store the item.
                skippedItems.Add(item);

                // Subtract one.
                skipped--;
            }
            else
            {
                // Yield the item.
                yield return item;
            }
        }
    }
}

private static IEnumerable<T> SliceEverything<T>(
    this IEnumerable<T> source, int count)
{
    // Test assertions.
    Debug.Assert(source != null);
    Debug.Assert(count > 0);

    // Create the helper.
    SliceHelper<T> helper = new SliceHelper<T>(
        source, count);

    // Return the helper concatenated with the skipped
    // items.
    return helper.Concat(helper.SkippedItems);
}

Ответ 3

Ближе всего в С# было бы использовать Enumerable.Skip и Enumerable.Take. Вы можете использовать их для создания своего нового списка.

Ответ 4

List<int> list1;

List<int> list2 = new List<int>(list1);

или вы можете

list2.AddRange(list1);

Чтобы получить отдельный список, используя LINQ

List<int> distinceList = list2.Distinct<int>().ToList<int>();

Ответ 5

Чтобы повернуть массив, сделайте a.Slice(1, null).Concat(a.Slice(null, 1)).

Здесь мой удар по нему. a.Slice(step: -1) дает обратную копию как a[::-1].

/// <summary>
/// Slice an array as Python.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="array"></param>
/// <param name="start">start index.</param>
/// <param name="end">end index.</param>
/// <param name="step">step</param>
/// <returns></returns>
/// <remarks>
/// http://docs.python.org/2/tutorial/introduction.html#strings
///      +---+---+---+---+---+
///      | H | e | l | p | A |
///      +---+---+---+---+---+
///      0   1   2   3   4   5
/// -6  -5  -4  -3  -2  -1    
/// </remarks>
public static IEnumerable<T> Slice<T>(this T[] array,
    int? start = null, int? end = null, int step = 1)
{
    array.NullArgumentCheck("array");
    // step
    if (step == 0)
    {
        // handle gracefully
        yield break;
    }
    // step > 0
    int _start = 0;
    int _end = array.Length;
    // step < 0
    if (step < 0)
    {
        _start = -1;
        _end = -array.Length - 1;
    }
    // inputs
    _start = start ?? _start;
    _end = end ?? _end;
    // get positive index for given index
    Func<int, int, int> toPositiveIndex = (int index, int length) =>
    {
        return index >= 0 ? index : index + length;
    };
    // start
    if (_start < -array.Length || _start >= array.Length)
    {
        yield break;
    }
    _start = toPositiveIndex(_start, array.Length);
    // end
    if (_end < -array.Length - 1)
    {
        yield break;
    }
    if (_end > array.Length)
    {
        _end = array.Length;
    }
    _end = toPositiveIndex(_end, array.Length);
    // slice
    if (step > 0)
    {
        // start, end
        if (_start > _end)
        {
            yield break;
        }
        for (int i = _start; i < _end; i += step)
        {
            yield return array[i];
        }
    }
    else
    {
        // start, end
        if (_end > _start)
        {
            yield break;
        }
        for (int i = _start; i > _end; i += step)
        {
            yield return array[i];
        }
    }
}

тесты nunit:

[Test]
// normal cases
[TestCase(3, 5, 1, 3, 4)]
[TestCase(0, 5, 1, 0, 4)]
[TestCase(3, null, 1, 3, 9)]
[TestCase(0, null, 1, 0, 9)]
[TestCase(null, null, 1, 0, 9)]
[TestCase(0, 10, 1, 0, 9)]
[TestCase(0, int.MaxValue, 1, 0, 9)]
[TestCase(-1, null, 1, 9, 9)]
[TestCase(-2, null, 1, 8, 9)]
[TestCase(0, -2, 1, 0, 7)]
// corner cases
[TestCase(0, 0, 1, null, null)]
[TestCase(3, 5, 2, 3, 3)]
[TestCase(3, 6, 2, 3, 5)]
[TestCase(100, int.MaxValue, 1, null, null)]
[TestCase(int.MaxValue, 1, 1, null, null)]
[TestCase(-11, int.MaxValue, 1, null, null)]
[TestCase(-6, -5, 1, 4, 4)]
[TestCase(-5, -6, 1, null, null)]
[TestCase(-5, -5, 1, null, null)]
[TestCase(0, -10, 1, null, null)]
[TestCase(0, -11, 1, null, null)]
[TestCase(null, null, 100, 0, 0)]
// -ve step
[TestCase(null, null, -1, 9, 0)]
[TestCase(-7, -5, -1, null, null)]
[TestCase(-5, -7, -1, 5, 4)]
[TestCase(-5, -7, -2, 5, 5)]
[TestCase(-7, null, -1, 3, 0)]
public void Slice01(int? s, int? e, int i, int? first, int? last)
{
    var a = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    var slice = a.Slice(start: s, end: e, step: i).ToArray();
    Print(slice);
    if (first.HasValue)
    {
        Assert.AreEqual(first, slice.First());
    }
    if (last.HasValue)
    {
        Assert.AreEqual(last, slice.Last());
    }
}