Related
Im just starting to learn how to use LinQ,
I want to only show grades that are 9 and 10 from a list i have but when trying to use var and foreach it wont let me, not sure why.
This is the list i was provided:
int[] grades= { 5, 9, 7, 8, 6, 9, 5, 7, 7, 4, 6, 10, 8 };
And here im trying to do the query:
var grades1 = from s in grades
where s.grades>= 9
select s;
foreach (var cal in grades)
Console.WriteLine(cal.grades);
The thing is that it shows an error when doing s.grades and cal.grades. I cant change the int[]grades.
The following works:
int[] grades = { 5, 9, 7, 8, 6, 9, 5, 7, 7, 4, 6, 10, 8 };
var grades1 = from s in grades
where s >= 9
select s;
foreach (var cal in grades1)
Console.WriteLine(cal);
s is an int so you can't qualify it. You are selecting an int element of an array of ints
try this
int[] grades = { 5, 9, 7, 8, 6, 9, 5, 7, 7, 4, 6, 10, 8 };
var grades1 = from s in grades
where s >= 9
select s;
foreach (var cal in grades1)
{
Console.WriteLine(cal);
}
I have a jagged array in a c# program that is declared where column one represents a year, column two represents the number of a month (1-12) and column three represents some data for that month:
double[][] data = new double[3][]
{
new double[] {1930,1931,1931,1931,1931,1931,1931,1931,1931,1931,1931,1931,1931,1932,1932,1932,1932,1932,1932,1932,1932,1932,1932,1932,1932},
new double[] {12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
new double[] {5, 6, 8, 3, 5, 8, 9, 6, 5, 6, 7, 5, 3, 2, 2, 2, 5, 7, 8, 3, 2, 2, 1, 2, 5}
};
As you can see, the first array is ordered. I would like to know how I could sort the jagged array by the second column , in ascending order like this.
{1931,1932,1931,1932,1931,1932,1931,1932,1931,1932,1931,1932,1931,1932,1931,1932,1931,1932,1931,1932,1931,1932,1930,1931,1932}
{1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12}
etc...
My question is, how would I be able to implement this using an insertion sort. It needs to be a custom algorithm and cannot make use of the Array.Sort algorithm that comes as part of C#
Thanks
The insertion sort algorithm can easily be generalized (abstracted) to work on indexes by defining two functions - one to compare two indexes and one to swap two indexes, like this:
public static class Algorithms
{
public static void InsertionSort(int start, int count, Func<int, int, int> compare, Action<int, int> swap)
{
for (int i = start + 1, end = start + count; i < end; i++)
for (int j = i; j > start && compare(j - 1, j) > 0; j--)
swap(j - 1, j);
}
}
Now you can achieve your goal by comparing second columns and swap all columns like this:
Algorithms.InsertionSort(0, data[1].Length,
(a, b) => data[1][a].CompareTo(data[1][b]),
(a, b) => { foreach (var col in data) Algorithms.Swap(ref col[a], ref col[b]); });
where Algorithms.Swap is another little helper:
public static void Swap<T>(ref T a, ref T b) { T c = a; a = b; b = c; }
I am trying to find position in a List based on where LINQ statement and get that item and next (x) amount. Example code:
List<int> numbers = new List<int>(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
numbers = numbers.Where(elt => elt == 6).Take(3).ToList();
I am trying to get back a filtered list of 6,7,8. However this is not working. Am I approaching this wrong?
Thanks in advance!
You almost got it. You just need to change the Where to a SkipWhile:
numbers = numbers.SkipWhile(elt => elt != 6).Take(3).ToList();
You have to use Where() overload that takes index of item as well and then use with indexOf():
List<int> numbers = new List<int>(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
var result = numbers.Where((x, i) => i >= numbers.IndexOf(6)).Take(3);
Here's another approach which comes into play when it's possible that the number is not unique and you want all occurences including the two next followers:
List<int> numbers = new List<int>(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 6, 7, 8, 9, 6 });
numbers = Enumerable.Range(0, numbers.Count)
.Where(index => numbers[index] == 6)
.SelectMany(index => numbers.Skip(index).Take(3))
.ToList(); // 6,7,8,6,7,8,6
I'm having trouble coming up with the most efficient algorithm to remove duplicates from List<List<int>>, for example (I know this looks like a list of int[], but just doing it that way for visual purposes:
my_list[0]= {1, 2, 3};
my_list[1]= {1, 2, 3};
my_list[2]= {9, 10, 11};
my_list[3]= {1, 2, 3};
So the output would just be
new_list[0]= {1, 2, 3};
new_list[1]= {9, 10, 11};
Let me know if you have any ideas. I would really appreciate it.
Build custom of EqualityComparer<List<int>>:
public class CusComparer : IEqualityComparer<List<int>>
{
public bool Equals(List<int> x, List<int> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(List<int> obj)
{
int hashCode = 0;
for (var index = 0; index < obj.Count; index++)
{
hashCode ^= new {Index = index, Item = obj[index]}.GetHashCode();
}
return hashCode;
}
}
Then you can get the result by using Distinct with custom comparer method:
var result = my_list.Distinct(new CusComparer());
Edit:
Include the index into method GetHashCode to make sure different orders will not be equal
This simple program does what you want:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication6
{
class Program
{
static void Main(string[] args)
{
List<List<int>> lists = new List<List<int>>();
lists.Add(new List<int> { 1, 2, 3 });
lists.Add(new List<int> { 1, 2, 3 });
lists.Add(new List<int> { 9, 10, 11 });
lists.Add(new List<int> { 1, 2, 3 });
var distinct = lists.Select(x => new HashSet<int>(x))
.Distinct(HashSet<int>.CreateSetComparer());
foreach (var list in distinct)
{
foreach (var v in list)
{
Console.Write(v + " ");
}
Console.WriteLine();
}
}
}
}
var finalList = lists.GroupBy(x => String.Join(",", x))
.Select(x => x.First().ToList())
.ToList();
You can use the LINQ Distinct overload that takes a comparer. The comparer should see if the lists are equal. Note that the default equals operations of lists won't do what you're really looking for, so the comparer will need to loop through each for you. Here's an example of such a comparer:
public class SequenceComparer<T> : IEqualityComparer<IEnumerable<T>>
{
IEqualityComparer<T> itemComparer;
public SequenceComparer()
{
this.itemComparer = EqualityComparer<T>.Default;
}
public SequenceComparer(IEqualityComparer<T> itemComparer)
{
this.itemComparer = itemComparer;
}
public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
{
if (object.Equals(x, y))
return true;
if (x == null || y == null)
return false;
return x.SequenceEqual(y, itemComparer);
}
public int GetHashCode(IEnumerable<T> obj)
{
if (obj == null)
return -1;
int i = 0;
return obj.Aggregate(0, (x, y) => x ^ new { Index = i++, ItemHash = itemComparer.GetHashCode(y) }.GetHashCode());
}
}
Update: I got the idea of using an anonymous type to make a better hash from Cuong Le's answer, and I LINQ-ified it and made it work in my class.
For small sets of data, a comparer could be useful, but if you have 1000 or more List> then trying to compare them all could begin to take a long amount of time.
I suggest that you instead use your data to build a distinct tree. The building of the tree will be much faster and when you are done you can always bring your data back into your old data structure.
I wanted to compare the performance of the answers of #Leniel Macaferi and #L.B as I wasn't sure which would be more performant, or if the difference would be significant. It turns out that the difference is very significant:
Method 1: 00:00:00.0976649 #Leniel Macaferi
Method 2: 00:00:32.0961650 #L.B
Here is the code I used to benchmark them:
public static void Main(string[] args)
{
var list = new List<List<int>> {new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3,}, new List<int> {1, 2, 31, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 6}, new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 9, 10, 11, 1}, new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 9}, new List<int> {1, 2, 31, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 6, 7}, new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 9, 10, 11}, new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3,}, new List<int> {1, 2, 31, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 6}, new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 9, 10, 11}};
var sw1 = new Stopwatch();
sw1.Start();
for (var i = 0; i < 1_000_000; i++)
{
var distinct = list.Select(x => new HashSet<int>(x)).Distinct(HashSet<int>.CreateSetComparer());
}
sw1.Stop();
Console.WriteLine($"Method 1: {sw1.Elapsed}");
var sw2 = new Stopwatch();
sw2.Start();
for (var i = 0; i < 1_000_000; i++)
{
var distinct = list.GroupBy(a => string.Join(",", a)).Select(a => a.First()).ToList();
}
sw2.Stop();
Console.WriteLine($"Method 2: {sw2.Elapsed}");
Console.ReadKey();
}
private int[, ,] table = new int[4 , 5 , 5]{
{{0,6,2,6,4},{2,2,4,2,8},{4,4,8,4,6},{6,6,2,6,4},{8,8,6,8,2}},
{{0,2,8,8,4},{2,4,6,6,8},{4,8,2,2,6},{6,2,8,8,4},{8,6,4,4,2}},
{{0,4,2,4,4},{2,8,4,8,8},{4,6,8,6,6},{6,4,2,4,4},{8,2,6,2,2}},
{{0,8,8,2,4},{2,6,6,4,8},{4,2,2,8,6},{6,8,8,2,4},{8,4,4,6,2}}
};
I want this table:
k|l 0 1 2 3 4
0 06264 22428 44846 66264 88682
1 02884 24668 48226 62884 86442
2 04244 28488 46866 64244 82622
3 08824 26648 42286 68824 84462
thanks for help
There's nothing wrong with your declaration. It compiles fine and I can write something like this:
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 5; j++)
{
for (int k = 0; k < 5; k++)
{
var x = table[i, j, k];
}
}
}
Update: sure you can shorten it a tiny bit. Since the array dimensions are given by your initial values, you can write it like this:
private int[,,] table = new [,,]{
<your numbers go here>
};
you need a 2 dimensional array, its [4,5] array
Try skipping the new int[4 , 5 , 5] part, the compiler should be able to find out the dimensions. Otherwise I don't see any problem.
Nothing is wrong. It works flawlessly for me. What problem exactly you have?
The compiler can figure out the length of each dimension for you, so let it do all the hard work:
private int[,,] table = new int[,,]{
{{0,6,2,6,4},{2,2,4,2,8},{4,4,8,4,6},{6,6,2,6,4},{8,8,6,8,2}},
{{0,2,8,8,4},{2,4,6,6,8},{4,8,2,2,6},{6,2,8,8,4},{8,6,4,4,2}},
{{0,4,2,4,4},{2,8,4,8,8},{4,6,8,6,6},{6,4,2,4,4},{8,2,6,2,2}},
{{0,8,8,2,4},{2,6,6,4,8},{4,2,2,8,6},{6,8,8,2,4},{8,4,4,6,2}}
};
And this gives you the output you want, apart from the header:
StringBuilder stringBuilder = new StringBuilder();
for (int row = 0; row < table.GetLength(0); ++row)
{
stringBuilder.Append(row.ToString() + "\t");
for (int column = 0; column < table.GetLength(1); ++column)
{
for (int valueIndex = 0; valueIndex < table.GetLength(2); ++valueIndex)
{
stringBuilder.Append(table[row, column, valueIndex].ToString());
}
stringBuilder.Append("\t");
}
stringBuilder.AppendLine();
}
string result = stringBuilder.ToString();
Console.WriteLine(result);
Just change new int[4 , 5 , 5] with new[,,]
this is what you should have :
var table = new[,,]
{
{{0, 6, 2, 6, 4}, {2, 2, 4, 2, 8}, {4, 4, 8, 4, 6}, {6, 6, 2, 6, 4}, {8, 8, 6, 8, 2}},
{{0, 2, 8, 8, 4}, {2, 4, 6, 6, 8}, {4, 8, 2, 2, 6}, {6, 2, 8, 8, 4}, {8, 6, 4, 4, 2}},
{{0, 4, 2, 4, 4}, {2, 8, 4, 8, 8}, {4, 6, 8, 6, 6}, {6, 4, 2, 4, 4}, {8, 2, 6, 2, 2}},
{{0, 8, 8, 2, 4}, {2, 6, 6, 4, 8}, {4, 2, 2, 8, 6}, {6, 8, 8, 2, 4}, {8, 4, 4, 6, 2}}
};
That piece of code won't compile if you have it in the wrong place - if you have it inside a function then drop the private modifier. (If it is declared at class level then it is fine).