Related
I searched, but I found only answers which related to two lists. But what about when they are more than two?
List 1 = 1,2,3,4,5
List 2 = 6,7,8,9,1
List 3 = 3,6,9,2,0,1
List 4 = 1,2,9,0,5
List 5 = 1,7,8,6,5,4
List 6 = 1
List 7 =
How to get the common items? as you can see one of them is empty, so the common will be empty, but I need to skip empty lists.
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());
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();
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);
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;
}
}
int[,] array2D = {{ 4, 7, 9, 3, 8, 6 },{ 4, 8, 6, 4, 8, 5 }};
how to add row 1 and 2
Possibly:
int[] sumRow = Enumerable.Range(0, array2D.GetLength(1))
.Select(i => array2D[0, i] + array2D[1, i]).ToArray();
I have been recently asked by a co-worker: Is it possible just take the first five elements and the last five elements by one query from an array?
int[] someArray = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
What I've tried:
int[] someArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
var firstFiveResults = someArray.Take(5);
var lastFiveResults = someArray.Skip(someArray.Count() - 5).Take(5);
var result = firstFiveResults;
result = result.Concat(lastFiveResults);
Is it possible to just take the first five elements and the last five elements by one query?
You can use a .Where method with lambda that accepts the element index as its second parameter:
int[] someArray = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
int[] newArray = someArray.Where((e, i) => i < 5 || i >= someArray.Length - 5).ToArray();
foreach (var item in newArray)
{
Console.WriteLine(item);
}
Output:
0, 1, 2, 3, 4, 14, 15, 16, 17, 18
A solution with ArraySegment<> (requires .NET 4.5 (2012) or later):
var result = new ArraySegment<int>(someArray, 0, 5)
.Concat(new ArraySegment<int>(someArray, someArray.Length - 5, 5));
And a solution with Enumerable.Range:
var result = Enumerable.Range(0, 5).Concat(Enumerable.Range(someArray.Length - 5, 5))
.Select(idx => someArray[idx]);
Both these solution avoid iterating through the "middle" of the array (indices 5 through 13).
In case you are not playing code puzzles with your co-workers, but just want to create a new array with your criteria, I wouldn't do this with queries at all, but use Array.copy.
There are three distinct cases to consider:
the source array has fewer than 5 items
the source array has 5 to 9 items
the source array has 10 or more items
The third one is the simple case, as the first and last 5 elements are distinct and well defined.
The other two require more thought. I'm going to assume you want the following, check those assumptions:
If the source array has fewer than 5 items, you will want to have an array of 2 * (array length) items, for example [1, 2, 3] becomes [1, 2, 3, 1, 2, 3]
If the source array has between 5 and 9 items, you will want to have an array of exactly 10 items, for example [1, 2, 3, 4, 5, 6] becomes [1, 2, 3, 4, 5, 2, 3, 4, 5, 6]
A demonstration program is
public static void Main()
{
Console.WriteLine(String.Join(", ", headandtail(new int[]{1, 2, 3})));
Console.WriteLine(String.Join(", ", headandtail(new int[]{1, 2, 3, 4, 5, 6})));
Console.WriteLine(String.Join(", ", headandtail(new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11})));
}
private static T[] headandtail<T>(T[] src) {
int runlen = Math.Min(src.Length, 5);
T[] result = new T[2 * runlen];
Array.Copy(src, 0, result, 0, runlen);
Array.Copy(src, src.Length - runlen, result, result.Length - runlen, runlen);
return result;
}
which runs in O(1);
If you are playing code puzzles with your co-workers, well all the fun is in the puzzle, isn't it?
It's trivial though.
src.Take(5).Concat(src.Reverse().Take(5).Reverse()).ToArray();
this runs in O(n).
Try this:
var result = someArray.Where((a, i) => i < 5 || i >= someArray.Length - 5);
This should work
someArray.Take(5).Concat(someArray.Skip(someArray.Count() - 5)).Take(5);
Try this:
int[] someArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 };
var firstFiveResults = someArray.Take(5);
var lastFiveResults = someArray.Reverse().Take(5).Reverse();
var result = firstFiveResults;
result = result.Concat(lastFiveResults);
The second Reverse() reorders the numbers so you won't get 18,17,16,15,14
Please try this:
var result = someArray.Take(5).Union(someArray.Skip(someArray.Count() - 5).Take(5));
Is there a way to access my three dimensional jagged array like this:
jaggedArray[1,2,3];
I got the following code snippets so far:
int[][] jaggedArray = new int[3][]
{
new int[] { 2, 3, 4, 5, 6, 7, 8 },
new int[] { -4, -3, -2, -1, 0, 1},
new int[] { 6, 7, 8, 9, 10 }
};
int[,,] dontWork = new int[,,] // expect 7 everywhere in the last dimension
{
{ { 2, 3, 4, 5, 6, 7, 8 } },
{ { -4, -3, -2, -1, 0, 1} },
{ { 6, 7, 8, 9, 10 } }
};
As for the first question, you're trying to access the 3rd element, of the 2nd element of the 1st element of the jagged array:
jaggedArray[1][2][3]
As for the error, a 3D array expects the same number of elements in each element of a dimension. Let's say, for simplicity's sake, that you have a 2D jagged array, a rough representation of what that looks like in memory would be:
First row -> 2, 3, 4, 5, 6, 7, 8
Second row -> -4, -3, -2, -1, 0, 1
Third row -> 6, 7, 8, 9, 10
You can see that each row is seen as a different array, and can therefore differ in size. A multidimensional array, however, does not have this property. It needs to be filled completely:
Column : 0 1 2 3 4 5 6
------------------------------------
First row : 2, 3, 4, 5, 6, 7, 8
Second row: -4, -3, -2, -1, 0, 1
Third row : 6, 7, 8, 9, 10
Your table is missing some cells, which makes no sense. You need to use the same number of elements per dimension.
You got the syntax for declaring 2D jagged array right, 3D jagged arrays are an extension of that. For example:
int[][][] jagged3d = new int[][][]
{
new int[][] { new int[] { 111, 112 }, new int[] { 121, 122, 123 } },
new int[][] { new int[] { 211 } }
}
But to access it, you need different syntax:
jagged3d[0][1][2]
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Lists permutations (unknown number)
Lets say I have input of Range[1, 8]
{1,2,3,4,5,6,7,8}
and i want to find Subsets[%, {2}] (all subsets with exact length of 2)
{{1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}, {1, 7}, {1, 8}, {2, 3}, {2, 4},
{2, 5}, {2, 6}, {2, 7}, {2, 8}, {3, 4}, {3, 5}, {3, 6}, {3, 7}, {3, 8},
{4, 5}, {4, 6}, {4, 7}, {4, 8}, {5, 6}, {5, 7}, {5, 8}, {6, 7}, {6, 8}, {7, 8}}
Tried:
var values = Enumerable.Range(1, 8);
var result = from v in values
from v2 in values.Skip(v)
select new[] { v, v2 };
Here is a function to find all combinations of an input sequence of a specified size:
public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> source, int n)
{
if (n == 0)
yield return Enumerable.Empty<T>();
int count = 1;
foreach (T item in source)
{
foreach (var innerSequence in source.Skip(count).Combinations(n - 1))
{
yield return new T[] { item }.Concat(innerSequence);
}
count++;
}
}
So in your case you'd use it as:
var result = Enumerable.Range(1, 8).Combinations(2);
var query = from a in Enumerable.Range(1, 8)
from b in Enumerable.Range(a + 1, 8 - a)
select String.Format("{{{0}, {1}}}", a, b);
foreach (string s in query)
{
Console.Out.WriteLine(s);
}
var lst = Enumerable.Range(1, 8);
var result = lst.Join(lst, c => 1, c => 1, (i, j) => new[] { i, j })
.Where(c => c[0] < c[1]);
Here I used the condition 1 == 1 to get the cross join of values in Enumerable.Range(1, 8) to get all possible combinations.
As noted in comments probably an easier way to generate a cross join is by:
var result = lst.SelectMany(_ => lst, (i, j) => new[] { i, j })
.Where(c => c[0] < c[1]);
but is less readable to my eyes.
Please note that this is little less efficient compared to other methods as this first gets all the possible combinations and then trim down the unwanted. Nevertheless a simple one-liner.