score:3

Accepted answer
var data = new [] {
    new List<int> {1, 2, 3, 4, 5},
    new List<int> {6, 7, 8, 9, 1},
    new List<int> {3, 6, 9, 2, 0, 1},
    new List<int> {1, 2, 9, 0, 5},
    new List<int> {1, 7, 8, 6, 5, 4},
    new List<int> {1},
    new List<int> {},
    null
};

IEnumerable<int> temp = null;
foreach (var arr in data)
    if (arr != null && arr.Count != 0)
        temp = temp == null ? arr : arr.Intersect(temp);

score:2

One way is to use a HashSet. You can put the items of the first collection in the hash, then iterate each collection after the first and create an new hash that you add items from the current collection to if it's in the hash. At the end you assign that common hash set to the overall one and break if it's every empty. At the end you just return the overall hash set.

public IEnumerable<T> CommonItems<T>(IEnumerable<IEnumerable<T>> collections)
{
    if(collections == null)
        throw new ArgumentNullException(nameof(collections));

    using(var enumerator = collections.GetEnumerator())
    {
        if(!enumerator.MoveNext())
            return Enumerable<T>.Empty();

        var overall = new HashSet<T>(enumerator.Current);
        while(enumerator.MoveNext())
        {
            var common = new HashSet<T>();
            foreach(var item in enumerator.Current)
            {
                if(hash.Contains(item))
                    common.Add(item);
            }

            overall = common;
            if(overall.Count == 0)
                break;
        }

        return overall;
    }
}

score:6

You can chain Intersect:

List<int> List1 = new List<int> {1, 2, 3, 4, 5};
List<int> List2 = new List<int> { 6, 7, 8, 9, 1 };
List<int> List3 = new List<int> { 3, 6, 9, 2, 0, 1 };
List<int> List4 = new List<int> { 1, 2, 9, 0, 5 };
List<int> List5 = new List<int> { 1, 7, 8, 6, 5, 4 };
List<int> List6 = new List<int> { 1 };

List<int> common = List1
  .Intersect(List2)
  .Intersect(List3)
  .Intersect(List4)
  .Intersect(List5)
  .Intersect(List6)
  .ToList();

score:6

var data = new List<List<int>> {
    new List<int> {1, 2, 3, 4, 5},
    new List<int> {6, 7, 2, 8, 9, 1},
    new List<int> {3, 6, 9, 2, 0, 1},
    new List<int> {1, 2, 9, 0, 5},
    new List<int> {1, 7, 8, 6, 2, 5, 4},
    new List<int> {1, 7, 2}
};


List<int> res = data
    .Aggregate<IEnumerable<int>>((a, b) => a.Intersect(b))
    .ToList();

The type of Aggregate is explicitly given, otherwise aggregation of two Lists would have to be List too. It can be easily adapted to run in parallel:

List<int> res = data
    .AsParallel<IEnumerable<int>>()
    .Aggregate((a, b) => a.Intersect(b))
    .ToList();

EDIT

Except... it does not run in parallel. The problem is operations on IEnumerable are deferred, so even if they are logically merged in parallel context, the actual merging occurs in the ToList(), which is single threaded. For parallel execution it would be better to leave IEnumerable and return to the Lists:

List<int> res = data
    .AsParallel()
    .Aggregate((a, b) => a.Intersect(b).ToList());

Related Query