Krythic
Krythic

Reputation: 4364

Resizing a List to fit a new Length

Suppose you have a list defined as:

List<string> list1 = new List<string>{"Cat","Dog","Bird","Badger"};

Now, suppose you wanted to write a generic function that could take that list and change the length of it. So if you're subtracting the length to make the list smaller, it would truncate the items within the list, or if the length is longer, it would copy the contents of the List and then add new additional indices to it.

A bigger length parameter would result in:

List<string> list1 = new List<string>{"Cat","Dog","Bird","Badger","","","","",""};

while a smaller length would result in:

List<string> list1 = new List<string>{"Cat","Dog"};

Assuming that no deep copying needed to be done, how could a function like this be written?

Upvotes: 0

Views: 1112

Answers (2)

Kroltan
Kroltan

Reputation: 5156

You can use AddRange and RemoveRange, which is better than looping with Add and/or RemoveAt:

public static void PaddedResize<T>(
    List<T> list,
    int size,
    T padding = default(T)
) {
    // Compute difference between actual size and desired size
    var deltaSize = list.Count - size;

    if (deltaSize < 0) {
        // If the list is smaller than target size, fill with `padding`
        list.AddRange(Enumerable.Repeat(padding, -deltaSize));
    } else {
        // If the list is larger than target size, remove end of list
        list.RemoveRange(size, deltaSize);
    }
}

This works for immutable, referentially transparent, or struct types, but for the garden variety class, it will pad the list with the same element over and over, which might be non-ideal. To fix that, take a factory function that creates the padding instead:

public static void PaddedResize<T>(
    List<T> list,
    int size,
    Func<T> paddingFactory // Changed parameter to a factory function
) {
    // Compute difference between actual size and desired size
    var deltaSize = list.Count - size;

    if (deltaSize < 0) {
        // If the list is smaller than target size, fill with the result of calling `paddingFactory` for each new item
        list.AddRange(Enumerable.Repeat(0, -deltaSize).Select(_ => paddingFactory()));
    } else {
        // If the list is larger than target size, remove end of list
        list.RemoveRange(size, deltaSize);
    }
}

Upvotes: 4

Nick Reshetinsky
Nick Reshetinsky

Reputation: 457

You may want to create some ListUtils class and write static generic functions there. In case you want a new list containing needed items

static class Listutils 
{
     public static List<T> Shrink<T>(List<T> src, Predicate<T> predicate) 
     {
         if (src == null || src.Count == 0) 
              return null;

         List<T> newList = new List<T>();
         foreach(T item in src) 
         {
            if (predicate(item))
                       newList.Add(item);   
         }

         return newList;
     }
}
........somewhere in your program 
  List<string> list = new List<string>{"Cat","Dog","Bird","Badger","Snake"};

  // select only Cat, Dog and Bird
  List<string> shrinked = ListUtils.Shrink(list, (name) => delegate 
  {
     return (name == "Cat" || name == "Dog" || name == "Bird");
  });

Upvotes: -2

Related Questions