Linq OrderBy last n values - c#

Lets say i have array of ints:
int[] values = new int[]{1,2,7,9,8,0};
How to OrderBy last 2 values?
int[] values = new int[]{1,2,7,9,0,8};

You can do it like this:
int[] values = new int[] { 1, 2, 7, 9, 8, 0 };
// Array.Sort accepts index and length, so you can sort only part of array
Array.Sort(values, values.Length - 2, 2);
// results in {1, 2, 7, 9, 0, 8}

Using the Generic Enumerable extensions, I came up with this. Don't think its the prettiest thing. Evk's solution looks much cleaner.
values = values.TakeWhile((n, index) => index < values.Length -2)
.Concat(
values.SkipWhile((n, index) => index < values.Length - 2).OrderBy(value => value)
).ToArray();

Try this
int[] values = new int[]{1,2,7,9,8,0};
var temp = values. Length > 1 ? new int[2] { values[length -2],values[values. Length-1] } : new inte[];
Var templist = values.tolist();
IF (values.length >1)
{
templist.removeat(values. Length-1)
templist.removeat(values.length-1)
}
templist.addrange(temp.tolist().orderby(x=> x))
Values= templist. Toarray()
Im writing from my mobile sorry for the unformated text

Related

C# Find all values in an array closest to a given number

given:
int[] myArray = new int[]{-8, -17, 12, 8, 16, -3, 7, 3};
Find all values in array closest to 0.
Currently using another code found on the site but it only tells me 1 value.
int nearest = myArray.Select(p => new {Value = p, Difference = Math.Abs(p - searchValue)}).OrderBy(p => p.Difference).First().Value;
In the current case both -3 and 3 are closest to 0 but since -3 comes first it only outputs -3.
Is there another way to do this where it finds all values instead of just First()?
Just to add to this. If you want to do this using O(n) complexity without sorting then you can do it this way :
public List<int> GetClosestNumbers(int searchVal)
{
int[] myArray = new int[] { -8, -17, 12, 8, 16, -3, 7, 3 };
int minimumDist = int.MaxValue;
List<int> output = new List<int>();
for (int i = 0; i < myArray.Length; i++)
{
var currentDistance = Math.Abs(myArray[i] - searchVal);
if (currentDistance < minimumDist)
{
minimumDist = currentDistance;
output.Clear();
output.Add(myArray[i]);
}
else if (minimumDist == currentDistance)
{
output.Add(myArray[i]);
}
}
return output;
}
Use a grouping on the lowest absolute value
int[] result = myArray
.OrderBy(i => Math.Abs(i - searchValue))
.GroupBy(i => Math.Abs(i - searchValue))
.First()
.ToArray();

How to get first index of Binary Search's results?

I have some problems. I have 2 list such as:
List<int> firstList = new List<int> { 1, 2, 2, 3, 5};
List<int> secondList = new List<int> { 2, 3, 1 };
⇒ True result is: {1, 3, 0}
I would like to get the first index of numbers in secondList that exists in firstList. I used list.BinarySearch() but the result was {2, 3, 0}.
List<int> firstList = new List<int> { 1, 2, 2, 3, 5};
List<int> secondList = new List<int> { 2, 3, 1 };
var output = secondList.Select(item => firstList.IndexOf(item)); // [1 , 3 , 0]
You can replace the IndexOf with a BinarySearch logic, but BinarySearch returns the first matched element index, so you won't get the lowest number, IndexOf does return the lowest matching index.
The problem is that when the list contains duplicate values as in your case, the BinarySearch method will return the index of any of the matching values (non deterministic).
To get the desired result, you could create and use a custom extension method like this:
public static class ListExtensions
{
public static int BinarySearchFirst<T>(this List<T> source, T item, IComparer<T> comparer = null)
{
if (comparer == null) comparer = Comparer<T>.Default;
int index = source.BinarySearch(item, comparer);
while (index > 0 && comparer.Compare(source[index], source[index - 1]) == 0)
index--;
return index;
}
}
Sample usage:
var result = secondList.Select(x => firstList.BinarySearchFirst(x)).ToList();
// { 1, 3, 0 }
C++ has a standard library function for this called lower_bound().
Here's a C# implementation. This is useful if you are searching large collections:
public static int LowerBound<T>(IList<T> values, T target, int first, int last)
where T : IComparable<T>
{
int left = first;
int right = last;
while (left < right)
{
int mid = left + (right - left) / 2;
var middle = values[mid];
if (middle.CompareTo(target) < 0)
left = mid + 1;
else
right = mid;
}
return left;
}
That doesn't return -1 for elements that it doesn't find, so to fix that we can wrap it like so:
public static int LowerBoundOrMinusOne<T>(IList<T> values, T target, int first, int last)
where T : IComparable<T>
{
int result = LowerBound(values, target, first, last);
if (result >= last || result < first || values[result].CompareTo(target) != 0)
return -1;
return result;
}
Here is how you use it:
List<int> firstList = new List<int> { 1, 2, 2, 3, 5 };
List<int> secondList = new List<int> { 2, 3, 1 };
List<int> result = secondList
.Select(value => LowerBoundOrMinusOne(firstList, value, 0, firstList.Count))
.ToList();
Console.WriteLine(string.Join(", ", result));
Of course, this is mainly of benefit to large lists because it has an O(Log2(N)) rather than an O(N) complexity.
Iterate through second array and get index of element in first array:
foreach (int item in secondList)
{
Console.WriteLine(firstList.IndexOf(item));
}
If you have a large firstList and so you have to use BinarySearch try amending it: find out the item (which is not guaranteed to be the leftmost one) by BinarySearch, then move to the left while having read the same item:
List<int> firstList = new List<int> { 1, 2, 2, 3, 5 };
List<int> secondList = new List<int> { 2, 3, 1, 123 };
var result = secondList
.Select(item => firstList.BinarySearch(item))
.Select(index => index < 0 ? -1 : Enumerable
.Range(0, index + 1) // we have to scan [0..index] at the worst case
.Select(i => index - i) // scan in reverse
.TakeWhile(i => firstList[index] == firstList[i]) // take while items are the same
.Last()); // finally, we want the last item
Test
// 1, 3, 0, -1
Console.Write(String.Join(", ", result));

Get common elements with index from two list C#

I have Two lists of type list<int> and i know we can find the common elements between two lists. But is there any way to get common elements and corresponding indexes of common elements in Intersected list or i need to go across each elements find the indexes.
LINQ has operations to project a sequence using indexes, but this isn't built into the query expression syntax, so you have to use "regular" extension method calls to start with. After that it's fairly easy, although probably just as simple not using LINQ, to be honest:
var pairs1 = list1.Select((value, index) => new { value, index });
var pairs2 = list2.Select((value, index) => new { value, index });
var matches = from pair1 in pairs1
join pair2 in pairs2 on pair1.value equals pair2.value
select new
{
Value = pair1.value,
Index1 = pair1.index,
Index2 = pair2.index
};
(You could use from pair2 in pairs2 where pair1.value == pair2.value if you'd prefer...)
Or non-LINQ (using Tuple<,,> for simplicity; other options are feasible):
var results = new List<Tuple<int, int, int>>();
for (int index1 = 0; index1 < list1.Count; index1++)
{
for (int index2 = 0; index2 < list2.Count; index2++)
{
if (list1[index1] == list2[index2])
{
results.Add(Tuple.Of(list1[index1], index1, index2);
}
}
}
Note that unlike a regular intersection operation, both of these can give you multiple results for the same value - because there can be multiple index pairs. For example, with lists of { 1, 2 } and {2, 2, 0}, you'd have tuples of (value=2,index1=1,index2=0), (value=2,index1=1,index2=1).
try below code
List<int> lstA = new List<int>() { 10, 2, 7, 9, 13, 21, 17 };
List<int> lstB = new List<int>() { 2, 10, 7, 21, 13, 9, 17 };
var lstA_Temp = lstA.Select((value, index) => new { index, value }).ToList();
var lstB_Temp = lstB.Select((value, index) => new { index, value }).ToList();
List<int> result = (from A in lstA_Temp from B in lstB_Temp
where A.index == B.index where A.value == B.value
select A.value).ToList();
you can also do this thing without linq see below logic
List<int> lstA = new List<int>() { 10, 2, 7, 9, 13, 21, 17 };
List<int> lstB = new List<int>() { 2, 10, 7, 21, 13, 9, 17 };
List<int> lstResult = new List<int>();
for (int i = 0; i < lstA.Count; i++)
{
if (lstA[i] == lstB[i])
lstResult.Add(lstA[i]);
}

Sort list based on multiple conditions

I have a list of integer lists, like that:
A -> 10 10 1 1 1
B -> 10 9 9 7 6
...
I would like to sort them based on how many 10s they have, then on how many 9s, 8s, 7s, and so on untile the 1s
So in the example above A should be better than B because even if it has less total points, it has two 10s instead of only 1.
Code should be generic because I don't know how many numbers will be available for each case (sometimes 10, sometimes 5, or even only 3).
I developed something like that:
lists.OrderByDescending(a => a.Where(b => b == 10).Count()).
ThenByDescending(a => a.Where(b => b == 9).Count()).
and so on, but this is not generic...
I hope the question is clear... thank you very much!
You can create query which orders lists by count of 10s, then compose query by adding additional orderings for numbers from 9 to 1:
var query = lists.OrderByDescending(l => l.Count(x => x == 10));
for (int i = 9; i >= 1; i--)
query = query.ThenByDescending(l => l.Count(x => x == i));
For these sample lists:
var lists = new[] {
new[] { 10, 9, 9, 8, 7 },
new[] { 10, 9, 9, 7, 6 },
new[] { 10, 10, 1, 1, 1 }
};
Result will be:
[10, 10, 1, 1, 1]
[10, 9, 9, 8, 7]
[10, 9, 9, 7, 6]
It's simple, but not very efficient. If you need better performance, then consider creating custom comparer. Here is sample with comparer which uses zipped ordered sequences to check if all items in sequences are same, or get first item which is different:
public class CustomComparer : Comparer<IList<int>>
{
public override int Compare(IList<int> x, IList<int> y)
{
var comparisons = x.Zip(y, (a,b) => a.CompareTo(b));
foreach(var comparison in comparisons)
{
if (comparison != 0)
return comparison;
}
return x.Count.CompareTo(y.Count);
}
}
NOTE: If items in lists are not ordered, then you should sort them before zipping:
var comparisons =
x.OrderByDescending(i => i)
.Zip(y.OrderByDescending(i => i), (a,b) => a.CompareTo(b));
It works very simple. Consider two lists:
[10, 9, 9, 8, 7, 5]
[10, 9, 9, 7, 6]
It will create pairs of items in corresponding positions:
{10,10}, {9,9}, {9,9}, {8,7}, {7,6}
Then items in each pair will be compared one by one, until first mismatch will be found:
0, 0, 0, 1 (four comparisons only)
That means first list has more 8s than second one. Usage:
var query = lists.OrderByDescending(i => i, new CustomComparer());
Result is same.
The following comparer
public class Comparer : IComparer<IEnumerable<int>>
{
public int Compare(IEnumerable<int> a, IEnumerable<int> b)
{
var aOrdered = a.OrderByDescending(i => i).Concat(new[] { int.MinValue });
var bOrdered = b.OrderByDescending(i => i).Concat(new[] { int.MinValue });
return a.Zip(b, (i, j) => i.CompareTo(j)).FirstOrDefault(c => c != 0);
}
}
lets you order you lists of lists like so
var result = lists.OrderByDescending(i => i, new Comparer());
without iterating through each list ten times counting individual elements.
This compares the lists and returns conventional comparison result - 1, 0, or -1 is returned depending on whether one value is greater than, equal to, or less than the other.
static int CompareLists(List<int> a, List<int> b)
{
var grpA = a.GroupBy(p => p).ToDictionary(k=>k.Key,v=>v.Count());
var grpB = b.GroupBy(p => p).ToDictionary(k=>k.Key,v=>v.Count());
for (int i = 10; i >= 0; i--)
{
int countA = grpA.ContainsKey(i) ? grpA[i] : 0;
int countB = grpB.ContainsKey(i) ? grpB[i] : 0;
int comparison = countA.CompareTo(countB);
if (comparison != 0)
return comparison;
}
return 0;
}
First we convert the lists into dictionary of number->amount of occurences.
Then we iterate through numbers from 10 to 0 and compare the number of occurences. If the result is 0, then we go to another number.
If you have List<List<int>> to sort, just use list.Sort(CompareLists) as in:
List<int> d = new List<int> { 10, 6, 6 };
List<int> b = new List<int> { 10, 9, 9 };
List<int> a = new List<int> { 10, 10, 1, 1, 1 };
List<int> c = new List<int> { 10, 7, 7 };
List<int> e = new List<int> { 9, 3, 7 };
List<int> f = new List<int> { 9, 9, 7 };
List<List<int>> list = new List<List<int>>() { a, b, c, d, e, f };
list.Sort(CompareLists);

How can you select all even numbered position items from IEnumerable?

How can you select all even numbered position from IEnumerable?
Say I have IEnumerable<int> as
3,5,7,9,10
Output should be 5, 9.
Which lambda do I need to write?
Use the overload of Enumerable.Where with the predicate function that also takes the index:
IEnumerable<int> result = ints.Where((x, i) => i % 2 == 1);
Something like this:
var nums = new int[] { 3, 5, 7, 9, 10 };
var results = nums.Where((n, i) => i % 2 != 0);
Here's what you need:
int[] values = new[] {3,5,7,9,10};
var everyOtherValue = values.Where((v, idx) => idx % 2 != 0);

Categories

Resources