I have a list of integer numbers and I want to remove from this list the couples of consecutive numbers.
For example, from this list:
{ 1, 2, 3, 4, 5, 100, 11, 12, 100, 14, 15, 100, 7, 8, 9, 100, 26, 27 }
I want to have this result:
{ 1, 2, 3, 4, 5, 100, 100, 100, 7, 8, 9, 100 }
This is the executing code:
var list = new List<int> { 1, 2, 3, 4, 5, 100, 11, 12, 100, 14, 15, 100, 7, 8, 9, 100, 26, 27 };
list.Add(-1);
int counter = 0;
bool nonecons = false;
for (int i = 0; i < list.Count; i++)
{
if ((i + 1 < list.Count))
{
if ((list[i + 1] - list[i]) == 1)
{
counter++;
}
else
{
nonecons = true;
if (counter < 2 && nonecons == true)
{
if (list[i] != 100)
{
list.Remove(list[i]);
list.Remove(list[i - 1]);
}
counter = 0;
nonecons = false;
}
else if (counter >= 2 && nonecons == true)
{
counter = 0;
nonecons = false;
}
}
}
}
list.RemoveAt(list.Count - 1);
But when i run this code I have this unexpected result:
{ 1, 2, 3, 4, 5, 100, 100, 100, 7, 100 }
What I need to change?
The problem is the how you use an index value to iterate over the list and in which direction you iterate the indexer: "upwards" the list towards the end, combined with how/where you remove elements from the list.
Imagine a list with the elements 100,14,15,100,100,7,8,9,100 (to take a snippet from your example list). Your code is processing this and is at index position being 3, pointing at the element 100 after element 15, when we start looking at what the code is doing:
100, 14, 15,100,100, 7, 8, 9,100
--- --- --- --- --- --- --- --- ---
^
i=3
Your code correctly detected that 14,15 is a consecutive sequence of a length smaller than 3, and proceeds to remove them.
Now the list looks like 100,100,100,7,8,9,100. So far so good.
But, and herein lies the problem, the current index position value hasn't changed. It's still 3. And then comes the next iteration step, with the index position now being 4. So, the next element considered by your code after deleting 14,15 is the element 8:
100,100,100, 7, 8, 9,100
--- --- --- --- --- --- ---
^
i=4
Because the element positions/indices have shifted to the left due to the removal of prior elements, but the index position hold in the i variable has not been adjusted to account for this shift, the code misses the 100 element in front of the 7 element and the 7 element itself.
This leads your code to detect only the consecutive sequence 8,9 instead of 7,8,9 (due to it skipping over the 7), hence it proceeds deleting 8,9.
The solution to your problem should now be clear: Whenever deleting elements in front of or at the index position held by i, you'll need to adjust the value of i to follow the left-shift of the elements after the removed elements.
This is done by decreasing the value of i by the amount of elements deleted in front or at the i position:
list.Remove(list[i]);
list.Remove(list[i - 1]);
i -= 2;
(As an alternative solution, the direction of iterating over the list could be switched to go "downwards" from the end towards the beginning of the list. Then any elements subject to removal would be behind the index position hold by i. And since i is only decreasing in this approach, the value in i wouldn't need to be adjusted because any elements still to be iterated over wouldn't have their position shifted. However, this would require significantly more changes to your code and isn't done with adding a single code line like i -= 2;)
(There are other concerns to be found with your code, like the not very useful nonecons variable that has not discernible effect, but it's unrelated to the problem with the incorrect result, so it's not really an issue...)
Related
Firstly I would like to say that the main principal of this question is not necessarily related to the revit API.
I am trying to create a "path of travel line" which has to go from the furthest point in a room following the shortest way along the wall, which means that there are 2 options the path can go(I added a picture for clarification)
I have an array of all the wall lines which are bordering this room, I have the index of the wall where the door is in and the index of the wall which has the furthest point in the room. However these indexes and the number of walls in the array vary from room to room.
How can I create 1 list that runs from doorIndex going up to furthestPointIndex and another list going from furthestPointIndex down to doorIndex considering that one of those 2 lists are going to just over from the end of a list(List.Count) to the beginning(List[0]) or the other way around.
From these 2 lists it would be easy for me to determine the shortest route
//this gets the walls in order in a list
List<Curve> edgeLoop = AbcRevitUtils.GeometryUtils.get_Curves(bottomFace);
Curve doorCurve;
Curve furthestCurve;
int index = edgeLoop.IndexOf(doorCurve);
int indexFar = edgeLoop.IndexOf(furthestCurve);
XYZ furthestPoint = new XYZ(0, 0, 0);
int startOrEnd;
//determine furthest endpoint on the furthest curve, a curve has 2 points in this case, a start point(0) and endpoint(1)
if (dPoint.DistanceTo(edgeLoop[indexFar].GetEndPoint(0)) < dPoint.DistanceTo(edgeLoop[indexFar].GetEndPoint(1)))
{
furthestPoint = edgeLoop[indexFar].GetEndPoint(1);
startOrEnd = 1;
}
else
{
furthestPoint = edgeLoop[indexFar].GetEndPoint(0);
startOrEnd = 0;
}
//this creates the line
Autodesk.Revit.DB.Analysis.PathOfTravel route = Autodesk.Revit.DB.Analysis.PathOfTravel.Create(doc.ActiveView, furthestPoint, dPoint);
//calculate which route in the loop is the shortest
//...
double path1 = 0;
List<double> path2 = new List<double>();
for (int i = index; i < indexFar; i++)
{
path1 += edgeLoop[i].Length;
}
if (index < indexFar)
{
for (int i = indexFar - 1; i > index - 1; i--)
{
int j = 0;
route.InsertWaypoint(edgeLoop[i].GetEndPoint(startOrEnd), j);
j++;
route.Update();
}
}
else
{
for (int i = indexFar + 1; i < index + 1; i++)
{
int j = 0;
route.InsertWaypoint(edgeLoop[i].GetEndPoint(startOrEnd), j);
j++;
route.Update();
}
}
Based on the question title (at the time of writing this answer):
Trying to create 2 lists of an array based on 2 indexes
and your supplementary comment:
For example in this case I would have a list of 4 items which are the walls, [0,1,2,3] . Lets say the Door Wall is on index 1 and the furthestPointWall is on index 3 then I need 1 list that is [3,2,1] and another list that is [3,0,1]
, I believe you in fact do not need help finding the shortest path, as may be the interpretation based on the content of your question post (and the comments related to it).
I think you rather want to generate
one list of wall indices that are being traversed when "going left" from S to D, and
one list of wall indices that are being traversed when "going right" from S to D,
when S is the starting point wall index and D is the door wall index.
As an example: If our wall indices are 0--5, starting point wall index is 3 and door wall index is 1:
[ 0, 1, 2, 3, 4, 5 ]
D S
, the two ways of traversing the wall indices should be as follows:
[ 0, 1, 2, 3, 4, 5 ]
D<----S // "going left"
[ 0, 1, 2, 3, 4, 5 ]
-->D S------ // "going right"
, resulting in these two lists:
[ 3, 2, 1 ] // "going left"
[ 3, 4, 5, 0, 1 ] // "going right"
( Is this a false interpretation? If so, please let me know, and I will delete this answer. )
One way to go about it could be:
Find the count of wall indices for one of the paths (path A)
Find the count of wall indices for the other path (path B)
Create an empty list for the wall indices for each path, each having its calculated capacity
(found in the two previous steps)
Find out whether path A moves up or down (i.e. "left" or "right") the wall index list
Populate list of walls (or wall indices) to traverse for path A and path B
Use the direction found in the previous step to ensure that path A and path B traverse the wall index list in opposite directions
Use the remainder operator % to enable "looping" the wall index list
(i.e. "jumping" from the last element to the first, or vice versa)
Seeing as the items in your comment's example ([0, 1, 2, 3]) have identical values as their respective indices in the list, I am not sure whether you are actually looking for resulting lists containing indices or resulting lists containing values from the original list.
I will therefore provide an example implementation which displays both approaches:
var walls = new List<int> { 10, 11, 12, 13, 14, 15 };
var indexStart = 3;
var indexDoor = 1;
var indexDiff = indexDoor - indexStart;
// Steps 1, 2
var wallCountPathA = 1 + Math.Abs(indexDiff);
var wallCountPathB = 2 + walls.Count - wallCountPathA;
// Step 3
// Indices
var wallIndicesPathA = new List<int>(wallCountPathA);
var wallIndicesPathB = new List<int>(wallCountPathB);
// Walls
var wallsPathA = new List<int>(wallCountPathA);
var wallsPathB = new List<int>(wallCountPathB);
// Step 4
var directionA = Math.Sign(indexDiff);
// Step 5
for (var i = 0; i < Math.Max(wallCountPathA, wallCountPathB); i++)
{
if (i < wallCountPathA)
{
var indexA = indexStart + (directionA * i);
wallIndicesPathA.Add(indexA); // Indices
wallsPathA.Add(walls[indexA]); // Walls
}
if (i < wallCountPathB)
{
var indexB = (walls.Count + indexStart - (directionA * i)) % walls.Count;
wallIndicesPathB.Add(indexB); // Indices
wallsPathB.Add(walls[indexB]); // Walls
}
}
This code snippet will result in:
Wall indices in path A: [ 3, 2, 1 ]
Wall indices in path B: [ 3, 4, 5, 0, 1 ]
Walls in path A: [ 13, 12, 11 ]
Walls in path B: [ 13, 14, 15, 10, 11 ]
Example fiddle here.
Note:
This implementation will not suffice for D == S.
In such a scenario, Math.Sign() will return 0 (rather than -1 or 1); leading to no incrementation (or decrementation) of the value being added to wallIndicesPathB as the for loop is being iterated.
Consider the int array below of n elements.
1, 3, 4, 5, 7. In this example the second last item is 5. I want to get the number of elements in this array before the second last value. There are 3 elements before the second last element. I will store the result in an int variable to use later. We obviously take into account that the array will have more than two element all the time.
This array will have different size everytime.
How can I achieve this in the most simplistic way?
The answer will always be n-2, so a very quick solution is to use .Length property and to subtract 2.
You can use Range from C# 8:
int[] arr = new int[]{1, 3, 4, 5, 7};
int[] newArr = arr.Length>=2 ? arr[..^2] : new int[0];
This will return all elements except the last 2, or an empty array if the lenght is less than 2. If it is guaranteed that the array will always have more than 2 elements, then you can simplify:
int[] newArr = arr[..^2];
If you are only interested about the quantity of the numbers then .Length-2 is the best way as it was stated by others as well.
If you are interested about the items as well without using C# 8 features then you can use ArraySegment (1).
It is really powerful, like you can reverse the items without affecting the underlying array.
int[] arr = new int[] { 1, 3, 4, 5, 7 };
var segment = new ArraySegment<int>(arr, 0, arr.Length - 2);
var reversedSegment = segment.Reverse(); //ReverseIterator { 4, 3, 1 }
//arr >> int[5] { 1, 3, 4, 6, 7 }
Please bear in mind that the same is not true for Span (2).
var segment = new Span<int>(arr, 0, arr.Length - 2);
segment.Reverse();
//arr >> int[5] {4, 3, 1, 6, 7 }
There is a ReadOnlySpan, which does not allow to perform such operation as Reverse.
If you would need that then you have to manually iterate through that in a reversed order.
I want to sort a list of integers in such a way that they end up being spread out as much as possible. Assuming base 8, the order of items between 1 and 7 ought to be: {4, 6, 2, 7, 1, 5, 3} as per:
There is a fair amount of ambiguity of course, as both 6 and 2 are equally far away from 4, 0 and 8, so the specific ordering of 6 and 2 is irrelevant. What I'm trying to achieve is to first pick the number furthest away from 0 and base, then pick the number furthest away from 0, base and first number, etc. Any multiple of the base will never occur so I don't care how that is handled.
I can manually design the sort order for any given base, but I need this to work for any base >= 2. Is there a clever/fast way to compute this or do I need to lazily build the sorting mapping tables and cache them for future use?
int SortOrder(int radix, int value)
{
int offset = value % radix;
int[] table = {int.MinValue, 4, 2, 6, 0, 5, 1, 3}; // Hand-crafted for base-8
return table[offset];
}
This is specifically not an answer to the question since it doesn't attempt to find the answer quickly. Rather it builds a dictionary of cached sorting values for each radix.
#region sorting logic
/// <summary>
/// Maintains a collection of sorting maps for all used number bases.
/// </summary>
private static readonly Dictionary<int, int[]> _sortingTable = new Dictionary<int, int[]>();
private static readonly object _sortingLock = new object();
/// <summary>
/// Compute the sorting key for a given multiple.
/// </summary>
/// <param name="radix">Radix or base.</param>
/// <param name="multiple">Multiple.</param>
/// <returns>Sorting key.</returns>
public static int ComputeSortingKey(int radix, long multiple)
{
if (radix < 2)
throw new ArgumentException("Radix may not be less than 2.");
if (multiple == 0)
return int.MinValue; // multiple=0 always needs to be sorted first, so pick the smallest possible key.
int[] map;
if (!_sortingTable.TryGetValue(radix, out map))
lock (_sortingLock)
{
map = new int[radix];
map[0] = -1; // Multiples of the radix are sorted first.
int key = 0;
HashSet<int> occupancy = new HashSet<int> { 0, radix };
HashSet<int> collection = new HashSet<int>(1.ArrayTo(radix)); // (ArrayTo is an extension method in this project)
while (collection.Count > 0)
{
int maxValue = 0;
int maxDistance = 0;
foreach (int value in collection)
{
int distance = int.MaxValue;
foreach (int existingValue in occupancy)
distance = Math.Min(distance, Math.Abs(existingValue - value));
if (distance > maxDistance)
{
maxDistance = distance;
maxValue = value;
}
}
collection.Remove(maxValue);
occupancy.Add(maxValue);
map[maxValue] = key++;
}
_sortingTable.Remove(radix); // Just in case of a race-condition.
_sortingTable.Add(radix, map);
}
long offset = multiple % radix;
if (offset != 0)
if (multiple < 0)
offset = radix - (Math.Abs(multiple) % radix);
return map[(int)offset];
}
#endregion
My original answer was to find the maximum delta. To work your way from out to in, use the same comparison but different selects:
List<double> answer = new List<double>();
List<double> doub = new List<double>() { 0, -1, 2, 3, 4, -5, 7 };//SORT this list for sorted results!
List<double> lowerHalf = new List<double>();
List<double> upperHalf = new List<double>();
for (int i = 0; i < doub.Count; i++)
{
if (i <= (int)Math.Floor((double)doub.Count / 2))
lowerHalf.Add(doub[i]);
else
upperHalf.Add(doub[i]);
}
if (upperHalf.Count < lowerHalf.Count)
{
upperHalf.Insert(0,lowerHalf[lowerHalf.Count-1]);
}
//if(upperHalf[0]==lowerHalf[lowerHalf.Count-1]){double median = lowerHalf[lowerHalf.Count-1]+upperHalf[1])/2;lowerHalf[lowerHalf.Count-1] = median; upperHalf[0]=median;}//use Math.Round or Math.Floor/Ceiling if necessary
for (int i = 0; i < lowerHalf.Count; i++)
{
double deltas = Math.Sqrt(Math.Pow(upperHalf[upperHalf.Count - (i + 1)] - lowerHalf[i], 2));
answer.Add(deltas);
Console.WriteLine("The answer for {1}, {2} is: {0}", deltas, lowerHalf[i], upperHalf[upperHalf.Count - (i+1)]);
}
Console.ReadLine();
This will provide:
The answer for 0, 7 is: 7
The answer for -1, -5 is: 4
The answer for 2, 4 is: 2
The answer for 3, 3 is: 0
NOTE that in the event of an odd number of items in the original range, this method uses the same item for both upper and lower lists. I've added a line to use the "actual" median for your benefit
To get rid of duplicates, use a hashset, union, or distinct()
Original answer - to find maximum delta):
You can use math in your Linq, like:
List<double> doub = new List<double>() { 0, 1, 2, 3, 4, 5, 7 };
double deltas = doub.Select(p => p - doub.First()).OrderBy(p => p).Last();
Console.WriteLine("The answer is: {0}",deltas);
Console.ReadLine();
If your values go negative, you'd need to use squares:
double deltas = Math.Sqrt( doub.Select(p => Math.Pow(p - doub.First(), 2)).OrderBy(p => p).Last());
or Math.Abs or a test to see which is larger - but this should give you an idea on how to get started. If the numbers aren't in order in the original list, you can call an orderby before the select, as well.
Literally:
List<double> doub = new List<double>() { 0, 1, 2, 3, 4, 5, 7 };
double deltas = Math.Sqrt( doub.Select(p => Math.Pow(p - doub.First(), 2)).OrderBy(p => p).Last());
Console.WriteLine("The answer is: {0}",deltas);
Console.ReadLine();
produces
'OilTracker.vshost.exe' (CLR v4.0.30319: OilTracker.vshost.exe): Loaded 'C:\Users\User\Documents\Visual Studio 2015\Projects\OilTracker\OilTracker\bin\Debug\TDAInterface.dll'. Symbols loaded.
'OilTracker.vshost.exe' (CLR v4.0.30319: OilTracker.vshost.exe): Loaded 'C:\Users\User\Documents\Visual Studio 2015\Projects\OilTracker\OilTracker\bin\Debug\BackFeeder.exe'. Symbols loaded.
The answer is: 7
Moving forward to sorting the list, use:
List<double> answer = new List<double>();
List<double> doub = new List<double>() { 0, 1, 2, 3, 4, 5, 7 };
//sort doub if necessary
foreach (double num in doub)
{
double deltas = Math.Sqrt(Math.Pow(doub.Select(p => p - num).OrderBy(p => p).Last(), 2));
answer.Add(deltas);
Console.WriteLine("The answer for {1} is: {0}", deltas,num);
}
Console.ReadLine();
(Again, use another orderby if the list is not in order).
Produces:
'OilTracker.vshost.exe' (CLR v4.0.30319: OilTracker.vshost.exe): Loaded 'C:\Users\User\Documents\Visual Studio 2015\Projects\OilTracker\OilTracker\bin\Debug\TDA_Stream_Interface.dll'. Symbols loaded.
The answer for 0 is: 7
The answer for 1 is: 6
The answer for 2 is: 5
The answer for 3 is: 4
The answer for 4 is: 3
The answer for 5 is: 2
The answer for 7 is: 0
The squares/square root help us change signs and deal with negatives - so
List<double> doub = new List<double>() { 0, -1, 2, 3, 4, -5, 7 };
Produces:
The answer for 0 is: 7
The answer for -1 is: 8
The answer for 2 is: 5
The answer for 3 is: 4
The answer for 4 is: 3
The answer for -5 is: 12
The answer for 7 is: 0
(which aren't in order because I failed to sort the list on either the inbound or outbound sides).
After running, the list "answer" will contain the results - the lowest delta can be accessed by answers.First() and the highest by answers.Last(). similar deltas will exist for different numbers the same number of units apart - you could use a HashSet conversion in the formula if you want to eradicate duplicate deltas. If you need help with that, please let me know.
If you need to store the numbers that created the delta as well as the delta itself, they are available to you in the For/Each loop as the Console.WriteLine() indicates.
If you want to work the range-to-median on both sides of the median, it's probably a good idea to split the list and work in pairs. Make 0 to median in one list, and median to endRange in the second list, work out in the first and in in the second. This should get you there, but if you need help getting over that final hump, let me know.
Hope this helps!!
I am writting algorithm for intersection of two arrays A and B , I want an optimized solution in terms of space complexity and time complexity.
I have written algorithm and it works fine but i want to know if there is any more optimal solution then this exist or if someone could provide me.
What i do is:
(1) Find the Smallest size array among two.
(2) The new array wil be of size allocated size equal to smaller size array
(3) From smaller size array i go and compare with each element in bigger array if it exists one ,i get it in third array"C" and break it right there (because we need to find intersection, even if it repeats 100 times after
we don't care for us only one existence is enough to put in third array). At the same time we also have to check if the element in smaller array which to be compared with all elements in bigger array already exist in third array, Example A=[0,1,1], B[0,1,2,3].
Now we start with A's first element, it is present in array B we save it in C[0], then go to second , now C is [0,1], and in next step we again have 1 to compare, which we have already compared.So for this situation we have to do check if element to be compare already exist in array C then we eliminate check for it.
(4) We store the found element in C (third array) and print it.
My full working code for it is :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int[] aar1 = { 0, 1, 1, 7, 2, 6, 3, 9, 11, 2, 2,3,3,3,3,3,1 };
int[] aar2 = { 0, 1, 2, 3, 4, 5, 6, 11, 11, 1, 1, 1, 1 };
int[] arr3 = findIntersection(aar1, aar2);
Console.WriteLine("the array is : " + arr3);
Console.ReadKey();
}
private static int[] findIntersection(int[] aar1, int[] aar2)
{
int[] arr3 = { 0 };
if (aar1.Count() < aar2.Count())
{
int counter = 0;
arr3 = new int[aar1.Count()];
foreach (int var1 in aar1)
{
if (!checkifInThirdArray(var1, arr3))
{
foreach (int var2 in aar2)
{
if (var1 == var2)
{
arr3[counter++] = var1;
break;
}
}
}
}
}
else
{
int counter = 0;
arr3 = new int[aar1.Count()];
foreach (int var2 in aar2)
{
if (!checkifInThirdArray(var2, arr3))
{
foreach (int var1 in aar1)
{
if (var2 == var1)
{
arr3[counter++] = var2;
break;
}
}
}
}
}
return arr3;
}
private static bool checkifInThirdArray(int var1, int[] arr3)
{
bool flag = false;
if (arr3 != null)
{
foreach (int arr in arr3)
{
if (arr == var1) { flag = true; break; }
}
}
return flag;
}
}
}
One space complexity issue i found is (the others i would really appreciate if you let me know with solution if you find any) :
(1) When i allocate the size to third array, i allocate the Min of the two arrays to be compared, In case if the intersection element are too less then we
have unnecessarily allocated the extra memory. How to solve this issue ?
Please note that i don't have to use any inbuilt function like intersection() or any other.
It sounds like your solution is an O(n2) one in that, for every single element in one array, you may need to process every single element in the other (in the case where the intersection is the null set). You should be aware that C# actually has facilities for finding the intersection of arrays but, should you wish to implement your own, read on.
You would probably be better of sorting both arrays (in-place if allowed otherwise to a separate collection) then doing a merge-check of the two to construct another. The sort could be O(n log n) and the merge check would be O(n).
If you're wondering what I mean by merge check, it's simply processing both (sorted) arrays side by side.
If the first element in both matches, you have an intersect point and you should store that value and advance both lists until the next value is different.
If they're different, there's no intersect point and you can advance the array with the lowest value until it changes.
By way of example, here's some code in Python (the ideal pseudo-code language) that implements such a solution. Array a contains all the multiples of three between 0 and 18 inclusive (in arbitrary order and including duplicates), while array b has all the even numbers in that range (again, with some duplicates and ordered "randomly").
a = [0,3,15,3,9,6,12,15,18,6]
b = [10,0,2,12,4,6,18,8,16,10,12,6,14,16]
# Copy and sort.
a2 = a; a2.sort()
b2 = b; b2.sort()
# Initial pointers and results for merge check.
ap = 0
bp = 0
c = []
# Continue until either array is exhausted.
while ap < len(a2) and bp < len(b2):
# Check for intersect or which list has lowest value.
if a2[ap] == b2[bp]:
# Intersect, save, advance both lists to next number.
val = a2[ap]
c.append(val)
while ap < len(a2) and a2[ap] == val:
ap += 1
while bp < len(b2) and b2[bp] == val:
bp += 1
elif a2[ap] < b2[bp]:
# A has smallest, advance it to next number.
val = a2[ap]
while ap < len(a2) and a2[ap] == val:
ap += 1
else:
# B has smallest, advance it to next number.
val = b2[bp]
while bp < len(b2) and b2[bp] == val:
bp += 1
print(c)
If you run that, you'll see the intersect list that's formed between the two arrays:
[0, 6, 12, 18]
Maybe I am not understanding you right but why don't you use the following;
int[] aar1 = { 0, 1, 1, 7, 2, 6, 3, 9, 11, 2, 2,3,3,3,3,3,1 };
int[] aar2 = { 0, 1, 2, 3, 4, 5, 6, 11, 11, 1, 1, 1, 1 };
aarResult = aar1.Intersect(aar2).ToArray();
This will result in an array with only the space needed and intersects the arrays. You can also initialize the aarResult as follows to get the minimum array size:
int[] aarResult = new int[Math.Min(aar1.Count(), aar2.Count())];
You can use LINQ Intersect method. It uses hashing and works for linear O(N+M) which is faster than your algorithm:
int[] aar1 = { 0, 1, 1, 7, 2, 6, 3, 9, 11, 2, 2, 3, 3, 3, 3, 3, 1 };
int[] aar2 = { 0, 1, 2, 3, 4, 5, 6, 11, 11, 1, 1, 1, 1 };
int[] result = aar1.Intersect(aar2).ToArray();
It will also solve your unnecessarily allocated items problem, because it will create an array of the exact answer size.
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