Add distinct items from a list to another list - c#

I would like to accomplish what the title states but I don't know how to go about doing so.
I have 2 lists:
public List<int[,]> LongList = new List<int[,]>();
public List<int[,]> UniqueList = new List<int[,]>();
To further explain, here's a scenario:
Puzzles:
public int[,] puzzle1 = new int [3,3] { {1,2,3},
{8,4,0},
{7,6,5} }; //[1,2,3;8,4,0;7,6,5]
public int[,] puzzle2 = new int [3,3] { {8,7,6},
{1,0,5},
{2,3,4} }; //[8,7,6;1,0,5;2,3,4]
public int[,] puzzle3 = new int [3,3] { {7,6,3},
{1,0,2},
{8,4,5} }; //[7,6,3;1,0,2;8,4,5]
LongList contains:
LongList.Add(puzzle1);
LongList.Add(puzzle1);
LongList.Add(puzzle1);
LongList.Add(puzzle1);
LongList.Add(puzzle2);
LongList.Add(puzzle2);
LongList.Add(puzzle3);
LongList.Add(puzzle3);
LongList.Add(puzzle3);
I would like Unique list to hold the UNIQUE values from LongList.
AS IF this happened:
UniqueList.Add(puzzle1);
UniqueList.Add(puzzle2);
UniqueList.Add(puzzle3);
As an equation: UniqueList = Distinct values from LongList
List is full of multiple reoccurring values & I would like to take only the unique ones and put them into UniqueList.
I'm trying to complete a puzzle and the LongList will contain multiple references of the same same puzzle and more. To make it simple for case of discussion:
LongList values: 1,1,1,1,2,2,3,4,4,4,4,5,5
I would like UniqueList to contain the puzzles: 1,2,3,4,5

OP's comments are vague.
Option 1: Unique numbers from across all multidimensional arrays
List<int> UniqueList = new List<int>();
UniqueList = LongList.Select(i => Flatten(i))
.SelectMany(i => i)
.Distinct()
.ToList();
This would turn { [[0, 1], [2, 3]], [[2, 2], [4, 5]] } to { 0, 1, 2, 3, 4, 5 }
See below for Flatten
Option 2: Unique multidimensional arrays by values
NB: Assumes size and number of dimensions of each multidimensional array match.
List<int[,]> UniqueList = new List<int[,]>();
foreach (var e in LongList)
{
IEnumerable<int> flat = Flatten(e);
if (!UniqueList.Any(i => Flatten(i).SequenceEqual(flat)))
{
UniqueList.Add(e);
}
}
This would turn { [[0, 1], [2, 3]], [[0, 1], [2, 3]], [[2, 2], [4, 5]] } to { [[0, 1], [2, 3]], [[2, 2], [4, 5]] }
See below for Flatten
Option 3: Unique references only
UniqueList = aList.Distinct().ToList();
NB: This was the original answer, for context on the comments.
Flatten Method
In all cases Flatten is taken from Guffa's SO Answer
public static IEnumerable<T> Flatten<T>(T[,] items) {
for (int i = 0; i < items.GetLength(0); i++)
for (int j = 0; j < items.GetLength(1); j++)
yield return items[i, j];
}
Other options
If OP would like something else (e.g. flattenting List<int[,]> to List<int[]> or support for different sized multidimensional arrays) they will have to comment back.

Based on OP's update, we just need to remove duplicate references. So we do not need to compare on a per-value basis. Distinct should do:
UniqueList = LongList.Distinct().ToList();

Related

Operate LINQ queries on 'vertical' rather than 'horizontal' space

I can't figure out how to do this, if even possible.
An example:
int[][] myArrays = {
new int[] {1, 2, 3},
new int[] {4, 5, 3},
new int[] {1, 2, 3}
};
int[] avgArray = myArrays.//Some LINQ statement to average every Nth element in the second dimension (essentially "flatten" the array)
//avgArray == {2, 3, 3}
To do this so far, I can only think of:
int ndDimLen = myArrays.GetLength(1);
int[] avgArray = new int[ndDimLen];
myArrays.Select(
arr => arr.Select( (n, i) => avgArray[i] += n )
);
avgArray = avgArray.Select( n => n / ndDimLen ).ToArray();
But this defeats the purpose, and isn't a particularly good idea on jagged arrays...
Also, I'd definitely like to avoid transposition, as it's quite a slow operation when operating on large arrays!
Thank you for your time!
You could iterate throught the [Columns] index while a [Row].Length reports that it contains a [Column] in the dimension whose values you need to average.
(Using the terms Column and Row for simplicity, as a visual aid)
An example, using Linq's .Average() to compute the average value of the sequence:
int[][] myArrays = {
new int[] {1, 2, 3},
new int[] {4, 5, 3},
new int[] {1, 2, 3},
};
int column = 2;
double avg = myArrays.Select((arr, i) => myArrays[i][column]).Average();
Result: 3
With a more complex structure, we need to verify whether the current [Column] contains a value:
int[][] myArrays = {
new int[] {1, 2, 3},
new int[] {3, 4, 5},
new int[] {3, 4},
new int[] {1, 2, 3, 4},
new int[] {1},
new int[] {4, 5, 3}
};
int column= 2;
double? avg = myArrays.Select((arr, i) =>
((arr.Length > column) ? myArrays?[i][column] : null)).Average();
Result Column 1: { 1, 3, 3, 1, 1, 4 } => 2.1666666...
Result Column 2: { 2, 4, 4, 2, 5 } => 3.4
Result Column 3: { 3, 5, 3, 3 } => 3.5
Result Column 4: { 4 } => 4
Same method, applied to all the [Columns]:
var Averages = Enumerable.Range(0, myArrays.Max(Arr => Arr.Length))
.Select(col => myArrays
.Select((arr, idx) =>
((arr.Length > col) ? myArrays?[idx][col] : null))
.Average()).ToList();
Enumerable.Range gives some flexibility.
The code above generates a series of int elements starting from 0 and incrementing the value to the number of Colums in the Array (Max(Arr => Arr.Length) selects the Array's Row containing the higher number of elements).
So, you could average the numbers in the first Column only (Index = 0) with:
var Averages = Enumerable.Range(0, 1).Select( ... )
or from Columns 1 to 3 (Indexes 1 to 3):
var Averages = Enumerable.Range(1, 3).Select( ... )
Yes, it is possible, but not on this object.
Basically, myArrays is an array of arrays, so LINQ only sees one row at a time, you cannot make it to see columns, because it's just not how it works.
What you could do, is to transpose this "table" first, that is change places of columns and rows. How to do it has already been discussed here so I will just refer you to it.
Using knowledge how to transpose it, you can make a method that will do it, and use LINQ on it, like:
Transpose(myArray).Select(predicate);
You didn't specify what you want if the arrays have unequal length:
int[][] myArrays =
{
new int[] {1, 2},
new int[] {4, 5, 3, 7, 5, 3, 4, 5, 1},
new int[] {1, 2, 3}
};
Let's assume your arrays all have the same length.
If you plan to use this functionality regularly, consider writing an extension function for two dimensional arrays. See Extension Methods Demystified
public static IEnumerable<int> ToVerticalAverage(this int[][] array2D)
{
if (array2D == null) throw new ArgumentNullException(nameof(array2D);
// if input empty: return empty
if (array2D.Any())
{ // there is at least one row
// check number of columns:
int nrOfColumns = array2D.First().Length;
if (!array2D.All(row => row.Length == nrOfColumns)
{
// TODO: decide what to do if arrays have unequal length
}
// if here, at least one row, all rows have same number of columns
for(int columNr = 0; columNr < nrOfColumns; ++columNr)
{
yield return array2D.Select(row => row[i]).Average();
}
}
// else: no rows, returns empty sequence
}
Usage:
int[][] myInputValues = ...
IEnumerable<int> averageColumnValues = myInputValues.ToVerticalAverage();
If you have several functions where you need the values of the columns, write an extension function to fetch the columns (= transpose the matrix)
public static IEnumerable<IEnumerable<int>> Transpose(this int[][] array2D)
{
// TODO: check input
int nrOfColumns = array2D.First().Length;
for(int columNr = 0; columNr < nrOfColumns; ++columNr)
{
yield return array2D.Select(row => row[columnNr];
}
}
public static IEnumerable<int> ToVerticalAverage(this int[][] array2D)
{
// TODO: check input
foreach (IEnumerable<int> column in array2D.Transpose())
{
yield return column.Average();
}

Permutations of a list of objects without reverse duplicates in C#

How can i generate unique permutations such that if any two permutations are reverse of each other (i.e. [1,2,3,4] and [4,3,2,1]), they are considered equal and only one of them should be contained in the final result.
For Example:
Carrying out permutation on [1,2,3] should give the following result:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
This is code used but this generates all permutations including the reverse duplicates
static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> list, int length)
{
if (length == 1) return list.Select(t => new T[] { t });
return GetPermutations(list, length - 1)
.SelectMany((t) => list.Where(e => !t.Contains(e)),
(t1, t2) => t1.Concat(new T[] { t2 }));
}
Select only the permutations where the first element is smaller than the last.
Example:
var list = new List<int> { 1, 2, 3, 4 };
foreach (var permutation in GetPermutations(list, 3))
{
int[] array = permutation.ToArray();
if (array.First() < array.Last())
Console.WriteLine(string.Join(",", array));
}
You need some way of comparing the first and last object. You can also replace
if (array.First() < array.Last())
with
if (list.IndexOf(array.First()) < list.IndexOf(array.Last()))
or whatever works to distinguish 2 items.

How to add data from 1d to 2d array in C#

How can I add an array to another 2D array? For example
//change this
array2d = { {1,2,3}, {4,5,6} };
//to this
array2d = { {1,2,3}, {4,5,6}, {7,8,9} };
//by adding
array1d = {7,8,9};
Is there any better way other than create a new array, which is bigger than the old one, then copy the old array to the array?
I would recommend a List<List<int>> for something like this, unless you have a reason not to.
The code for it may look something like this:
List<List<int>> my2dList = new List<List<int>>()
{
new List<int>()
{
1,
2,
3
},
new List<int>()
{
4,
5,
6
},
};
my2dList.Add(new List<int>(){7,8,9});
Alternatively, if you really want to limit each column to a length of three, consider using an inner structure with an immutable size (array of size 3, etc)
It seems like you might want to use a different data structure, a list of arrays would make this much easier.
Extended version of the code snippet posted by #VP. includes the back-conversion from List(List> to Jagged Array using Linq:
// 2d array to List
List<List<int>> ar2list = new List<List<int>>()
{
new List<int>() { 1, 2, 3 },
new List<int>() { 4, 5, 6 },
};
// adding item to List
ar2list.Add(new List<int>() { 7, 8, 9 });
// List to Jagged array conversion using Linq
int[][] _arrConcat = ar2list.Select(Enumerable.ToArray).ToArray();
Finally, pertinent to this particular use-case as requested by OP, int[][] can be easily converted to int[,] with simple for loop:
array2d = new int[_arrConcat.Length, 3];
for (int i = 0; i<_arrConcat.Length; i++)
{
for (int j = 0; j < 3; j++)
{
array2d[i, j] = _arrConcat[i][j];
}
}
where array2d is the original array with added index/content.
Hope this will help. Best regards,

Reversing order of elements in multidimensional array

I have an array with elemnents in order 1,2,3,4,5 and I would need to reverse it so it will be 5,4,3,2,1.
What about the following pseudo code? Is here not an easier way
EDIT: I Am sorry I thought multidimensional array
someclass [,] temporaryArray=new someclass [ArrayLenght,ArrayLenght];
//for each dimension then
for(int I=0;I<ArrayLenghtOfDimension;I++)
{
temporaryArray[ArrayLenghtOfDimension-I]=Array[I];
}
Array=temporaryArray;
The array base class has a Reverse() extension method built in
int[] originalArray = new int[] { 1, 2, 3, 4, 5 };
int[] reversedArray = originalArray.Reverse().ToArray();
Note that the Reverse method returns IEnumerable, so you need to call ToArray() on the result.
And if you need to just iterate over the elements in the array, then all you need is
foreach (int element in originalArray.Reverse())
Console.WriteLine(element);
Oops - Reverse is on IEnumerable, not Array, so you can use that with any collection.
IEnumerable<int> IEnumerableInt = new List<int>() { 1, 2, 3 };
int[] reversedArray2 = IEnumerableInt.Reverse().ToArray();
Yes there is fast solution exists in .net
int[] values = new int[] { 1, 2, 3, 4, 5 };
Array.Reverse(values);
Your array is reversed. so you can iterate through it
foreach (int i in values)
{
Response.Write(i.ToString());
}
the above code will display
54321
It will also work for string[], char[] or other type of arrays
Event though the Array class has Reverse methods defined:
Array.Reverse(originalArray); // original array is now reversed
If all you need to do is iterate backwards over it do the following:
for(int I= ArrayLength - 1; I >= 0; I--)
{
}
This avoid re-allocating memory for the reversed array.
Array.Reverse is the best way to do this. Do you care about order of the elements at all? If so,then you can do the following.
int[] originalArray = new int[] { 10, 2, 13, 4, 5 };
int[] descOrderedArray = originalArray.OrderByDescending(i => i).ToArray();
int[] ascOrderedArray = originalArray.OrderBy(i => i).ToArray();
For a multi-dimensional array it's the same idea
int[][] multiDimArray = new int[][] { new int[] { 1, 2, 3 }, new int[] { 4, 5, 6 } };
int[][] reversedMultiArray = multiDimArray.Reverse().ToArray();
produces an array of two arrays that is: {4, 5, 6}, {1, 2, 3}

Get the first few elements from List on C#

I have List with n items. I wish transform my list to new list, in which no more than n first items.
Example for n=3:
[1, 2, 3, 4, 5] => [1, 2, 3]
[1, 2] => [1, 2]
What is the shortest way to do this?
If you have C# 3, use the Take extension method:
var list = new [] {1, 2, 3, 4, 5};
var shortened = list.Take(3);
See: http://msdn.microsoft.com/en-us/library/bb503062.aspx
If you have C# 2, you could write the equivalent:
static IEnumerable<T> Take<T>(IEnumerable<T> source, int limit)
{
foreach (T item in source)
{
if (limit-- <= 0)
yield break;
yield return item;
}
}
The only difference is that it isn't an extension method:
var shortened = SomeClass.Take(list, 3);
If you don't have LINQ, try:
public List<int> GetFirstNElements(List<int> list, int n)
{
n = Math.Min(n, list.Count);
return list.GetRange(0, n);
}
otherwise use Take.
You can use Take
myList.Take(3);
You can with Linq
List<int> myList = new List<int>();
myList.Add(1);
myList.Add(2);
myList.Add(3);
myList.Add(4);
myList.Add(5);
myList.Add(6);
List<int> subList = myList.Take<int>(3).ToList<int>();
var newList = List.Take(3);

Categories

Resources