TheBoubou
TheBoubou

Reputation: 19933

List, not lose the reference

Back from interview. I share with you and a good and precise answer is welcome.

The purpose, you have a static method, this method receive an IList<int> you have to get back the values you can divise by 3 and make the code.

Constraint : The original list (in the main) has a reference on the stack and the values on the heap, the result must be return (it's a void method) in the same space (on the heap) than the original list. The solution show here is not correct because in the method a new pointer on the stack + heap are created in the method domain. Solution ?

Bonus : how change the code to receive not only int but float, double, ....

static void Main(string[] args)
    {
        IList<int> list = new List<int>() { 9, 3, 10, 6, 14, 16, 20};
        CanBeDivedByThree(list);
    }

    static void CanBeDivedByThree(IList<int> list)
    {
        list = (from p in list
                where p % 3 == 0
                orderby p descending
                select p).ToList<int>();
    }

Upvotes: 4

Views: 1082

Answers (4)

Dirk Vollmar
Dirk Vollmar

Reputation: 176259

That's meaningless as the internal storage to an IList is not under your control. Adding (or possibly removing) items might re-allocate the internal data structures.

It is especially meaningless as the list in your sample contains value types which are copied anyway when you access them.

Last but not least it's basically the whole point of using a managed language that you don't have to worry about memory (al)locations. Such things are implementation details of the platform.

To take up on your bonus question: There is no simple way to achieve that. One could think that using generics with a type constraint would solve the problem here (something like static void CanBeDivedByThree<T>(IList<T> list) where T : struct), but the problem is that C# does not (yet?) have support for generic arithmetic. C# doesn't have a modulo operator that can take a generic parameter of type 'T' and 'int'.

Upvotes: 9

CodesInChaos
CodesInChaos

Reputation: 108880

Unfortunately only List but not IList does implement RemoveAll. So I first implement it as an extension method.

public static int RemoveAll<T>(this IList<T> list, Predicate<T> match)
{
  if (match == null)
    throw new ArgumentNullException("match");

  int destIndex=0;
  int srcIndex;
  for(srcIndex=0;srcIndex<list.Count;srcIndex++)
  {
    if(!match(list[srcIndex]))
    {
      //if(srcIndex!=destIndex)//Small optimization, can be left out
        list[destIndex]=list[srcIndex];
      destIndex++;
    }
  }
  for(int removeIndex=list.Count-1;removeIndex>=destIndex;removeIndex--)
  {
    list.RemoveAt(removeIndex);
  }
  return srcIndex-destIndex;
}

Then you can use:

list.RemoveAll(n => n % 3 != 0);

You can then use overloads for other types. Unfortunately you can't (easily) make it generic since generics don't work with operator overloading.

Upvotes: 2

Jon Skeet
Jon Skeet

Reputation: 1503469

Others have covered the list part - this is just for the bonus bit.

You can't do this in a statically typed way using C# generics, but if you're using C# 4 you can do it with dynamic typing. For example:

using System;
using System.Collections.Generic;

class Test
{
    static void Main()
    {
        ShowDivisibleBy3(new List<int> { 1, 3, 6, 7, 9 });
        ShowDivisibleBy3(new List<decimal> { 1.5m, 3.3m, 6.0m, 7m, 9.00m });
    }

    static void ShowDivisibleBy3<T>(IEnumerable<T> source)
    {
        foreach (dynamic item in source)
        {
            if (item % 3 == 0)
            {
                Console.WriteLine(item);
            }
        }
    }
}

Upvotes: 1

Vlad
Vlad

Reputation: 35594

list.RemoveAll(n => n % 3 == 0);

or

for (int i = list.Count - 1; i >= 0; --i)
{
    if (list[i] % 3 != 0)
        list.RemoveAt(i);
}

The first approach works only for List<T>.

One could make it a template method, but remainder operation doesn't make much sense on floats.

Upvotes: 2

Related Questions