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.
Related
I'm trying to program a Sudoku solver in C# in which I'm using a List of an integer array with all the positions of empty fields, because I need them in my algorithm.
In the progress of solving the Sudoku I need to remove those positions which got filled with a number. But somehow my list with empty positions does not get smaller, when I use the Remove-method.
I will explain my problem with a simplified example:
List<int[]> test1 = new List<int[]>();
test1.Add(new int[] { 0, 0 });
test1.Add(new int[] { 1, 7 });
test1.Remove(new int[] { 1, 7 });
The first line generates the list with my one dimensional integer array (which always consists of two values - one for the column and one for the row-number). The empty positions get added in a method, but in this example I just added them in these two lines.
Later on in my algorithm, I want to remove elements by using the Remove-function similarly to the Add-function. It throws no errors, even while compiling. However, it's not removing anything.
I tried using the RemoveAll-method, although I don't really understand, how it works and therefore didn't find a correct solution for my problem.
By trying out a List of integers (not an integer array) the Remove-method works perfectly, but in the case of an array it doesn't seem to work this way.
Even creating a seperat variable rem
int[] rem = new int[] { 1, 7 };
test1.Remove(rem);
does not work.
I'm a beginner so I don't really know if a List of arrays is the best solution in my case.
bool IntArrayPredicate(int[] element)
{
return element.SequenceEqual(new int[] { 2, 3 });
}
List<int[]> listOfIntArray = new List<int[]>();
listOfIntArray.Add(new int[] { 0, 0 });
listOfIntArray.Add(new int[] { 1, 7 });
listOfIntArray.Add(new int[] { 2, 3 });
listOfIntArray.RemoveAll(element => element.SequenceEqual(new int[] { 1, 7 })); //It Works!. Using lambda expresion. Remove by Comparing sequences that match equals.
int[] toRemove = listOfIntArray[0];
listOfIntArray.Remove(toRemove); //It works!. Remove element by exact reference.
listOfIntArray.Remove(new int[] { 2, 3 }); // Not working / References are different.
listOfIntArray.RemoveAll(IntArrayPredicate); // It works!. Same as using lambda but using method reference.
Console.WriteLine($"{nameof(listOfIntArray)} has {listOfIntArray.Count()} elements"); // Yup. 0 elements.
The reason you're not able to remove items from your list using the Remove method is that you're storing reference types in the List, but creating new references when trying to remove an item. Because reference types by default use a reference comparison (not a comparison of their fields) to determine equality, you won't be able to remove items in that way.
One way to resolve this is to create a reference to each object in the List<int[]> outside of the list creation itself. This way, you can use the existing reference as an argument to the Remove method, and, because it's referring to the same object that was added to the list, it will match and be removed:
// Here we have 'item1' and 'item2' that refer to the location of different int[]
int[] item1 = new int[] { 0, 0 };
int[] item2 = new int[] { 1, 7 };
// And now we use those references to add the int[] items to our list
List<int[]> test1 = new List<int[]>();
test1.Add(item1);
test1.Add(item2);
// Finally, we can remove an item using the same reference that we used to add it
test1.Remove(item2);
This is very clunky, however, since we now need to maintain an individual reference for every item in our list as well as the list itself.
Another way to resolve this would be to search for the item we want to remove using our own equality algorithm (rather than relying on the default equality that Remove uses). We can use FirstOrDefault to search for the first item that has a length of 2 and whose values match those that we want. It will return a reference to the item if it's found, or null if it's not found. We can use IndexOf to get the index of the item (or -1 if it's not found), and then pass that index to the RemoveAt method to remove it:
List<int[]> test1 = new List<int[]>();
test1.Add(new int[] { 0, 0 });
test1.Add(new int[] { 1, 7 });
int indexToRemove = test1.IndexOf(test1.FirstOrDefault(item =>
item.Length == 2 && item[0] == 1 && item[1] == 7));
if (indexToRemove >= 0) test1.RemoveAt(indexToRemove);
As you can see, what you're trying to do isn't super easy. As a suggestion to help you think about the problem in a different way, you might consider using a 2-dimensional array to store the sudoku grid. Normally we store the row in the first dimesion and the column in the second dimension:
int[,] grid = new int[9, 9];
You could potentially create a few of these, one to represent the puzzle solution, one to represent the puzzle shown to the user's (with just their guesses), maybe even one to store user's "notes" (if you allow them to tag a cell with possible values before committing to a guess), though that would likely need to be a string[,] or an int[,][].
Then the typical way to loop through the grid would be something like:
for (int row = 0; row < 9; row++)
{
for (int col = 0; col < 9; col++)
{
// Do something with the cell at 'row' 'col' here
// Set a value for this cell
grid[row, col] = row + col;
// Report the value of a cell
Console.WriteLine($"The value at row {row} and column {col} is {grid[row, col]}");
}
}
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
I have the below array:
int [] array = { 9, 8, 3, 2, 3, 2 };
I'd like to write a statement when i pick a number from array, it gives the following number as the result.
for examaple i pick the number 8 and according to the statement it gives to number 3 as result.
One way to do it is to use SkipWhile to reach the location of the search number, skip one, and take the first item after it:
var array = new[] { 9, 8, 3, 2, 3, 2 };
var next = array.SkipWhile(n => n != 8).Skip(1).First(); // next==3
This code assumes two things:
The search number 8 is there, and
The search number is not the last number in the sequence.
Demo.
If I understand your question correctly you want to return the next item in the array after the selection?
If that is the case you can do the following:
int index = Array.IndexOf(array, 8);
return array[index + 1];
There are some limitations to this implementation, please see here:
https://msdn.microsoft.com/en-us/library/7eddebat(v=vs.110).aspx
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.
I have an object that contains two arrays, the first is a slope array:
double[] Slopes = new double[capacity];
The next is an array containing the counts of various slopes:
int[] Counts = new int[capacity];
The arrays are related, in that when I add a slope to the object, if the last element entered in the slope array is the same slope as the new item, instead of adding it as a new element the count gets incremented.
i.e. If I have slopes 15 15 15 12 4 15 15, I get:
Slopes = { 15, 12, 4, 15 }
Counts = { 3, 1, 1, 2 }
Is there a better way of finding the i_th item in slopes than iterating over the Counts with the index and finding the corresponding index in Slopes?
edit: Not sure if maybe my question wasn't clear. I need to be able to access the i_th Slope that occurred, so from the example the zero indexed i = 3 slope that occurs is 12, the question is whether a more efficient solution exists for finding the corresponding slope in the new structure.
Maybe this will help better understand the question: here is how I get the i_th element now:
public double GetSlope(int index)
int countIndex = 0;
int countAccum = 0;
foreach (int count in Counts)
{
countAccum += count;
if (index - countAccum < 0)
{
return Slopes[countIndex];
}
else
{
countIndex++;
}
}
return Slopes[Index];
}
I am wondering if there is a more efficient way?
You could use a third array in order to store the first index of a repeated slope
double[] Slopes = new double[capacity];
int[] Counts = new int[capacity];
int[] Indexes = new int[capacity];
With
Slopes = { 15, 12, 4, 15 }
Counts = { 3, 1, 1, 2 }
Indexes = { 0, 3, 4, 5 }
Now you can apply a binary search in Indexes to serach for an index which is less or equal to the one you are looking for.
Instead of having an O(n) search performance, you have now O(log(n)).
If you are loading the slopes at one time and doing many of these "i-th item" lookups, it may help to have a third (or instead of Counts, depending on what that is used for) array with the totals. This would be { 0, 3, 4, 5 } for your example. Then you don't need to add them up for each look up, it's just a matter of "is i between Totals[x] and Totals[x + 1]". If you expect to have few slope buckets, or if slopes are added throughout processing, or if you don't do many of these look-ups, it probably will buy you nothing, though. Essentially, this is just doing all those additions at one time up front.
you can always wrap your existing arrays, and another array (call it OriginalSlopes), into a class. When you add to Slopes, you also add to OriginalSlopes like you would a normal array (i.e. always append). If you need the i_th slope, look it up in OriginalSlopes. O(1) operations all around.
edit adding your example data:
Slopes = { 15, 12, 4, 15 }
Counts = { 3, 1, 1, 2 }
OriginalSlopes = { 15, 15, 15, 12, 4, 15, 15 }
In counts object (or array in your base), you add a variable that has the cumulative count that you have found so far.
Using the binary search with comparator method comparing the cumulative count you would be able to find the slope in O(log N) time.
edit
`Data = 15 15 15 12 4 15 15`
Slopes = { 15, 12, 4, 15 }
Counts = { 3, 1, 1, 2 }
Cumulative count = { 3, 4, 5, 7}
For instance, if you are looking for element at 6th position, when you search into the Cumulative count dataset and find value 5, and know next value is 7, you can be sure that element at that index will have 6th position element as well.
Use binary search to find element in log(N) time.
Why not a Dictionary<double, double> with the key being Slopes and the value being counts?
Hmm, double double? Now I need a coffee...
EDIT: You could use a dictionary where the key is the slope and each key's value is a list of corresponding indexes and counts. Something like:
class IndexCount
{
public int Index { get; set; }
public int Count { get; set; }
}
Your collection declaration would look something like:
var slopes = new Dictionary<double, List<IndexCount>>();
You could then look up the dictionary by value and see from the associated collection what the count is at each index. This might make your code pretty interesting though. I would go with the list approach below if performance is not a primary concern.
You could use a single List<> of a type that associates the Slopes and Counts, something like:
class SlopeCount
{
public int Slope { get; set; }
public int Count { get; set; }
}
then:
var slopeCounts = new List<SlopeCount>();
// fill the list