Say I have a List of numbers:
var list = new List<int>{100, 1, 2, 4, 10, 11, 50, 54};
And I want the output to be sets of numbers that satisfy a condition of "closeness" with its adjacent values.
So for example, if I define the distance between adjacent numbers to be less than 5, I will get something like:
Set1: {100}
Set2: {1, 2, 4}
Set3: {10, 11}
Set4: {50, 54}
Since the numbers in each set are within 5 of its adjacent value.
How would I do this in LINQ? I was thinking of some combination of Aggregate() and TakeWhile() but I couldn't figure it out.
To be clear, I am looking for a generic way of solving this (i.e. an algorithm that if I change 5 to any other number would also give an output of sets that satisfy the new condition).
I'm sure there are better approaches, since you want to do it with Linq you could do something like this.
int gid=0, prevvalue = list[0];
va result = list.Select(x=>
{
var obj = Math.Abs(prevvalue-x)>=10?
new {gid= ++gid, item =x}
:new {gid= gid, item =x};
prevvalue= x;
return obj;
})
.GroupBy(x=>x.gid)
.Select(x=>x.Select(s=>s.item).ToList())
.ToArray();
Check this Demo
Related
How can I use Linq to check the previous Account Number to see if it matches the current account number and if it does make the amount = 0?
Thanks,
Mark
If you have a list of Account Numbers. You could use Enumerable.Range for comparing to the previous value
var accountNumbers = new List<int> { 0, 1, 2, 3, 4, 5, 5, 5, 6, 7, 3 };
var result = Enumerable.Range(1, accountNumbers.Count - 1)
.Select(i => accountNumbers[i] != accountNumbers[i - 1] ? accountNumbers[i] : 0)
.ToList();
First, we need to clarify what "make the amount = 0" means. LINQ sequences are implicitly immutable, hence it is not possible to modify the amount in-place, but we need to return a new sequence (if you do want to modify the amounts in-place I would recommend using an array and a normal loop).
The answer provided by #Max works in principle, but is not performant as lists (and many other collection types) have only slow access to random elements.
LINQ does not have convenient tools for the task out of the box. Using only in-built methods a solution could be:
IEnumerable<int> accountNumbers = new List<int> { 0, 1, 2, 3, 4, 5, 5, 5, 6, 7, 3 };
IEnumerable<double> amounts = new List<double> { 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 };
var possiblyInvalidAccountNumbers = accountNumbers.Skip(1); // The first account has no predecessor
var possiblyInvalidAmounts = amounts.Skip(1);
var validatedAmounts =
accountNumbers.Take(possiblyInvalidAccountNumbers.Count())
.Zip(possiblyInvalidAccountNumbers, (prevAccNo, accNo) => new { prevAccNo, accNo })
.Zip(possiblyInvalidAmounts, (numbers, amount) => numbers.prevAccNo != numbers.accNo ? amount : 0.0)
.Prepend(amounts.First());
Obviously, this code is somewhat convoluted, so a possible way to improve the clarity could be to write your own extension methods (e.g. a Zip3() method that takes three inputs would come in handy).
I have a scenario where I have to get paginated records in a reversed way using LINQ. Lets Assume I have 15 items in the order they were posted:
1, 2, 3, 4, 5.......... 15
Having a pages size of 5, if the user sends 1 as the currentPage in my method. Then I should be able to return 11, 12, 13, 14, 15 as the result set, if he sends 2 as the currentPage then I should return 6, 7, 8, 9, 10 and so on. How do I set the value that I give to the Skip method so that it would give me records in this way? And yes, I'm ordering the items in an ascending order by their dates too.
Just a simple example of the logic:
var nums = new[] {1, 2, 3, ..., 15};
var lastFew = nums.Reverse().Take(5).Reverse().ToArray();
Or alternatively, as a list:
var nums = new List<int> { 1, 2, 3, ..., 15};
nums.Reverse();
nums.RemoveRange(5); // removes from index 5 till end
nums.Reverse();
The actual implementation can vary depending on how your code is designed, etc, but that should get you started.
The key methods to use here are: Reverse, Take to limit the returned amount, and Skip to choose the starting index. If you use Skip, you can most likely avoid using Reverse altogether.
I would do like this (using EF):
var resultByDesc = db.Entities
.OrderByDescending(o => o.DateTime)
.Skip(page * itemsPerPage)
.Take(itemsPerPage)
.ToList(); // important! eager loading!
// it will be executed in your client side, not SQL.
var actualResult = resultByDesc.Reverse();
I have got this structure
var values = new Dictionary<int, List<Guid>>();
And I have to say if all dictionary elements has the same set of List<Guid>.
I dont need to know which are exactly are different, just to answer the question.
So it looks like
List A { 1, 2, 3} List B { 1, 2, 3} List C { 1, 2, 3} the same and have no difference.
and
List A { 3, 2, 3} List B { 1, 2, 3} List C { 1, 2, 3} are not the same.
I have no clue where I can start it.
Initially i guessed to convert List<Guid> to string and just do distinct operation over it.
But is this a good approach?
Thank you!
I'd create a HashSet<Guid> from one of the values (any) and then check that all of the others are equal to it:
// TODO: Handle the dictionary being empty
var firstSet = new HashSet<Guid>(values.First().Value);
var allEqual = values.All(pair => firstSet.SetEquals(pair.Value));
This assumes that:
The order within each list is unimportant
The number of times each GUID appears in the list is unimportant
(i.e. you really are thinking of them as sets, not lists, at least for this part of the code)
In other words, if you have guids A and B, the code above assumes that { A, B, B } is equivalent to { B, A }.
SequenceEquals() might be what you're looking for. Combine it with IEnumerable.All() and you can get a boolean answer whether all elements of your dictionary contain the same Lists. For instance:
values.All(list => values.All(list2 => list2.SequenceEquals(list));
My goal is to perform a binary search for only the first element in a 2D array. I have been searching all day to find if it is possible using BinarySearch() in .NET but I can't find a thing.
To make this clearer. Imagine I had a 1D array, unsorted. If I sort the array, I lose the original index. I would like to create a second element of my array to hold the original index (this I can do) then sort by first element, then binary search over the first elements.
If anyone could push me in the right direction I'd be very grateful.
Thanks
Well, if I understand you correctly, you need something like this:
// initialize the array and the indexes array
var a2D = new int[2][];
a2D[0] = new[] { 3, 14, 15, 92, 65, 35 }; // <-- your array (fake data here)
a2D[1] = Enumerable.Range(0, a2D[0].Length).ToArray(); // create the indexes row
// sort the first row and the second one containing the indexes
Array.Sort(a2D[0], a2D[1]);
// now a2D array contains:
// row 0: 3, 14, 15, 35, 65, 92
// row 1: 0, 1, 2, 5, 4, 3
// and you can perform binary search on the first row:
int columnIndexOf35 = Array.BinarySearch(a2D[0], 35);
// columnIndexOf35 = 3
//
// a2D[0][columnIndexOf35] = 35 <- value
// a2D[1][columnIndexOf35] = 5 <- original index
As per MSDN, Array.BinarySearch method operates only with one-dimensional arrays, so it is impossible to use it directly in your case. Some of the options you have are:
Extract first column into a separate array and call Array.BinarySearch on it.
Define custom class Pair that implements interface IComparable and construct your array with the instances of this class.
Implement binary search on two dimensional array by yourself.
It looks like you want to have object that holds data and "original index" and than sort/search array of objects by data.
(This answer shows Andrei's option 2)
class IndexedData:IComparable
{
public MyType Data;
public int OriginalIndex;
public int CompareTo(object obj) {
// add correct checks for null,.. here
// and return correct comparison result.
// I.e. if MyType is IComparable - just delegate.
return Data.CompareTo(obj);
}
Check IComparable on MSDN for implementation/usage details.
Depending on what you're planning to do with the arrays afterwards, another solution might be to use LINQ.
var unsortedStartingArray = new[] {3, 6, 2, 1, 20, 20};
var q = unsortedStartingArray
.Select((item, index) => new {item, index})
.ToLookup(x => x.item, x => x.index);
var notFound = q[30]; // An empty array. Nothing found
var indexOf1 = q[1].First(); // returns 3
var multipleIndexsOf20 = q[20]; // Returns an array with 4, 5
The index into the lookup would then be the value you're searching for. Performance wise I would guesstimate this to be faster aswell about 5 times slower from my crude testing.
I would like to have a nice clean LINQ code that can get an array of the index values of the top 1000 largest values inside an array.
For example:
int[] IndexArray = ArrayWithValues.Return_Indexes_Of_1000_Biggest_Values
The code is obviously bogus it is just to illustrate what I need.
UPDATE
I totally forgot to say that I need a second functionality. I have a second array, and I need to retrieve all the values in the second array which has the same indexes as contained inside the IndexArray.
I can do it easily using loops and all that but the code is big, and I want to learn to use LINQ more often but at the moment LINQ is still very foreign to me.
I have gone through similar questions asked here but I was not able to modify the code to suite my needs, since people usually only need the values and not the indexes of the values.
Thanks for the help!
Something like this should work. It uses the overload of Select that allows you to incorporate a second input that is the index of the item in the sequence.
var indexArray = sourceArray
.Select((value, index) => new { value, index })
.OrderByDescending(item => item.value)
.Take(1000)
.Select(item => item.index)
.ToArray();
Simply project the value and index into an object, order by the value, take the top 1000 items, and then select simply the indexes before converting to an array.
Testing by taking the top 5 indexes from the array { 10, 4, 6, 8, 2, 3, 5, 1, 9, 7 } yields { 0, 8, 3, 9, 2 }, which maps to values { 10, 9, 8, 7, 6 }.
As the comments have already addressed in regards to your update, you can simply take these indices to select from the other if you are confident the arrays are equal in length or will otherwise not result in an IndexOutOfBoundsException.
.Select(item => otherArray[item.index])
.ToArray();
Another method you could look up would be Enumerable.Zip.