I have a list.
1 2 3 4 5 6 7
I wish to return a list of differences (deltas) between consecutive element.
1 1 1 1 1 1
How can I do this?
I am sure there must be a simple "collections" way of doing this - but I cannot find it.
You can use Enumerable.Skip and the overload of Enumerable.Select which projects the index:
List<int> deltaList = list.Skip(1) // skip first, irrelevant
.Select((num, index) => num - list[index]) // index 0 is second number in list
.ToList();
The trick is that Skip(1) does not only skip the first number (which is desired) but also changes the indices in Select. The first number's index will be 0 but it'll refer to the second number in the list (due to Skip(1)). Therefore num - list[index] subtracts the current with the previous number.
var result = list.Zip(list.Skip(1), (x, y) => y - x);
Related
I’m having an issue with an algorithm I’m trying to implement in C# (the language doesn't matter much I guess).
Let’s say I have a list that could be of any length..for example:
var maxNumbers = new List<int>{5,3,2}();
The numbers in the list represent the maximum value of each entry. For example, the first entry means that it can be any number between 1 and 5 (5 is included).
Now, I want to print all combinations of every possible value for each entry in the list.
To explain:
The first number in the list is 5, so the possible values are 1,2,3,4,5
The second number in the list is 3, so the possible values
are 1,2,3
The last number in the list is 2, so the possible values
are 1,2
My algorithm should print something like:
1-1-1
1-1-2
1-2-1
1-2-2
1-3-1
1-3-2
1-2-1
etc.
I tried to implement this using recursion but wasn't able to get it. Here is my code:
void Iterate(List<int> numbers)
{
if (numbers.Count == 0)
{
Console.WriteLine("");
return;
}
int number = numbers[0];
for (int i = 1; i <= number; i++)
{
Console.WriteLine($"{i} ");
Iterate(numbers.Where((v, index) => index != 0).ToList());
}
}
Can anyone provide insights?
A non recursive approach;
We use Select(Enumerable.Range) to turn your list of maxes into a list of list of ints representing all the numbers..
Then we repeatedly use SelectMany to add another level to the list. SelectMany expects to be fed an enumerable. In the first instance there is only one item in combos, which gets crossed with 5 items from the first entry in ints, so SelectMany produces 5 items.
Second time round SelectMany effectively thinks it's expanding a "5 lists of 3 items" into a "list of 15 items". Third time round SelectMany thinks it's expanding a "15 lists of 2 items" into a "list of 30 items"...
public static string[] Combine(IEnumerable<int> maxes)
{
var ints = maxes.Select(max => Enumerable.Range(1, max));
IEnumerable<string> combos = new[] { "" };
foreach (var i in ints)
{
combos = combos.SelectMany(r => i.Select(x => r + (r == "" ? "" : "-") + x));
}
return combos.ToArray();
}
This answer fixes your code, the crucial problem with which, for me, was that the solution didn't carry any memory of where it had got to so far with making the output, so there isn't any way for iterate to repeat the earlier loop outputs
Here's the fixed code:
static void Iterate(List<int> numbers, string sofar)
{
if (numbers.Count == 0)
{
Console.WriteLine(sofar);
return;
}
for (int i = 1; i <= numbers[0]; i++)
{
Iterate(numbers.Skip(1).ToList(), sofar + i + " ");
}
}
Your code in the question hs a bit of a typo in that it does a WriteLine in the for loop which really messed up the output. Removing that to just Write you get:
1 1 1
2
2 1
2
3 1
2
2 1 1
2
2 1
2
3 1
2
3 1 1
2
2 1
2
3 1
2
4 1 1
2
2 1
2
3 1
2
5 1 1
2
2 1
2
3 1
2
If I add some spaces to change the alignment:
1 1 1
2 --> it's 1 1 2
2 1 --> it's 1 2 1
2 --> it's 1 2 2 etc
3 1
2
2 1 1
2
2 1
2
3 1
2
3 1 1
2
2 1
2
3 1
2
...
You can see it's nearly there, in that it's printing the number that changes each time, it's just lost any memory of what to print in terms of the numbers that haven't changed. The altered code passes the "string we generated so far" and devolves responsibility for printing it to just the if. Each time the loop calls Iterate it passes the string built so far so it keeps that memory of where it got up to
C# why does binarysearch have to be made on sorted arrays and lists?
Is there any other method that does not require me to sort the list?
It kinda messes with my program in a way that I cannot sort the list for it to work as I want to.
A binary search works by dividing the list of candidates in half using equality. Imagine the following set:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
We can also represent this as a binary tree, to make it easier to visualise:
Source
Now, say we want to find the number 3. We can do it like so:
Is 3 smaller than 8? Yes. OK, now we're looking at everything between 1 and 7.
Is 3 smaller than 4? Yes. OK, now we're looking at everything between 1 and 3.
Is 3 smaller than 2? No. OK, now we're looking at 3.
We found it!
Now, if your list isn't sorted, how will we divide the list in half? The simple answer is: we can't. If we swap 3 and 15 in the example above, it would work like this:
Is 3 smaller than 8? Yes. OK, now we're looking at everything between 1 and 7.
Is 3 smaller than 4? Yes. OK, now we're looking at everything between 1 and 3 (except we swapped it with 15).
Is 3 smaller than 2? No. OK, now we're looking at 15.
Huh? There's no more items to check but we didn't find it. I guess it's not in the list.
The solution is to use an appropriate data type instead. For fast lookups of key/value pairs, I'll use a Dictionary. For fast checks if something already exists, I'll use a HashSet. For general storage I'll use a List or an array.
Dictionary example:
var values = new Dictionary<int, string>();
values[1] = "hello";
values[2] = "goodbye";
var value2 = values[2]; // this lookup will be fast because Dictionaries are internally optimised inside and partition keys' hash codes into buckets.
HashSet example:
var mySet = new HashSet<int>();
mySet.Add(1);
mySet.Add(2);
if (mySet.Contains(2)) // this lookup is fast for the same reason as a dictionary.
{
// do something
}
List exmaple:
var list = new List<int>();
list.Add(1);
list.Add(2);
if (list.Contains(2)) // this isn't fast because it has to visit each item in the list, but it works OK for small sets or places where performance isn't so important
{
}
var idx2 = list.IndexOf(2);
If you have multiple values with the same key, you could store a list in a Dictionary like this:
var values = new Dictionary<int, List<string>>();
if (!values.ContainsKey(key))
{
values[key] = new List<string>();
}
values[key].Add("value1");
values[key].Add("value2");
There is no way you use binary search on unordered collections. Sorting collection is the main concept of the binary search. The key is that on every move u take the middle index between l and r. On first step they are 0 and size - 1, after every step one of them becomes middle index between them. If x > arr[m] then l becomes m + 1, otherwise r becomes m - 1. Basically, on every step you take half of the array you had and, of course, it remains sorted. This code is recursive, if you don't know what recursion is(which is very important in programming), you can review and learn here.
// C# implementation of recursive Binary Search
using System;
class GFG {
// Returns index of x if it is present in
// arr[l..r], else return -1
static int binarySearch(int[] arr, int l,
int r, int x)
{
if (r >= l) {
int mid = l + (r - l) / 2;
// If the element is present at the
// middle itself
if (arr[mid] == x)
return mid;
// If element is smaller than mid, then
// it can only be present in left subarray
if (arr[mid] > x)
return binarySearch(arr, l, mid - 1, x);
// Else the element can only be present
// in right subarray
return binarySearch(arr, mid + 1, r, x);
}
// We reach here when element is not present
// in array
return -1;
}
// Driver method to test above
public static void Main()
{
int[] arr = { 2, 3, 4, 10, 40 };
int n = arr.Length;
int x = 10;
int result = binarySearch(arr, 0, n - 1, x);
if (result == -1)
Console.WriteLine("Element not present");
else
Console.WriteLine("Element found at index "
+ result);
}
}
Output:
Element is present at index 3
Sure there is.
var list = new List<int>();
list.Add(42);
list.Add(1);
list.Add(54);
var index = list.IndexOf(1); //TADA!!!!
EDIT: Ok, I hoped the irony was obvious. But strictly speaking, if your array is not sorted, you are pretty much stuck with the linear search, readily available by means of IndexOf() or IEnumerable.First().
I'm trying to slice a List of strings (size N) and return a range based on the list being sliced into equal parts (X).
So for instance, if I have a list of say 10 elements, and my number of tiers is 5.
Elements 0 and 1 are tier 1. Elements 2 and 3 are tier 2. At the end of the method I return the tier specified in the params.
What I'm struggling with is if the list count isn't divisible by the number of tiers. For instance, 23 / 5 = 4.6. So that means they'll be 5 sets of 4, and then 3 left over. I'd like the result to be 5 tiers of 5, 5, 5, 5, 3 (with the final tier just the remaining number of elements).
I've included my code so far, but I'm really stuck on how to ensure the list sizes are as equal as possible and how to handle remainders.
// Gets a list and returns a range by the tier specified
public List<string> GetRangeByTierIndex(List<string> listToDivide, int numOfTiers, int tierIndexToGet)
{
int numOfElementsPerList = listToDivide.Count / numOfTiers;
int index = (tierToGet - 1) * numOfElementsPerList;
return listToDivide.GetRange(index, numOfElementsPerList);
}
Note: Forgot to mention, I can't use LINQ for this either (AOT and iOS problems).
The idea is to use modulo which is remainder of division of listToDivide.Count by numOfTiers. If that remainder is greater than zero all tiers which index is less or equal to that remainder will have one more element. Because of that, start index of every tier must be corrected also. Note that I haven't wrote any checks (like if number of elements in main list is zero, numOfTiers < tierIndexToGet, etc... but you can add those checks if you need). Also, this will, for your example, give lists with 5, 5, 5, 4, 4 elements instead of 5, 5, 5, 5, 3 but I think this is even better. Anyway I hope it will be good for your needs. Code should look something like:
public List<string> GetRangeByTierIndex(List<string> listToDivide, int numOfTiers, int tierIndexToGet)
{
int remaining = listToDivide.Count % numOfTiers;
int numOfElementsPerList = listToDivide.Count / numOfTiers;
int index = (tierIndexToGet - 1) * numOfElementsPerList;
if (remaining > 0)
{
// most increase position of index because of numOfElementsPerList correction bellow
index += tierIndexToGet > remaining ? remaining : tierIndexToGet - 1;
// first 'remaining-th' tiers will have +1 element
numOfElementsPerList += tierIndexToGet <= remaining ? 1 : 0;
}
return listToDivide.GetRange(index, numOfElementsPerList);
}
Example: 23 and 5.
23/5 = 4 // 4 tiers of 5 - use integer division
23%5 = 3 // 1 tier of 3
I'm trying to get a list of string ordered such that the longest are on either end of the list and the shortest are in the middle. For example:
A
BB
CCC
DDDD
EEEEE
FFFFFF
would get sorted as:
FFFFFF
DDDD
BB
A
CCC
EEEEE
EDIT: To clarify, I was specifically looking for a LINQ implementation to achieve the desired results because I wasn't sure how/if it was possible to do using LINQ.
You could create two ordered groups, then order the first group descending(already done) and the second group ascending:
var strings = new List<string> {
"A",
"BB",
"CCC",
"DDDD",
"EEEEE",
"FFFFFF"};
var two = strings.OrderByDescending(str => str.Length)
.Select((str, index) => new { str, index })
.GroupBy(x => x.index % 2)
.ToList(); // two groups, ToList to prevent double execution in following query
List<string> ordered = two.First()
.Concat(two.Last().OrderBy(x => x.str.Length))
.Select(x => x.str)
.ToList();
Result:
[0] "FFFFFF" string
[1] "DDDD" string
[2] "BB" string
[3] "A" string
[4] "CCC" string
[5] "EEEEE" string
Don't ask how and why... ^^
list.Sort(); // In case the list is not already sorted.
var length = list.Count;
var result = Enumerable.Range(0, length)
.Select(i => length - 1 - 2 * i)
.Select(i => list[Math.Abs(i - (i >> 31))])
.ToList();
Okay, before I forget how it works, here you go.
A list with 6 items for example has to be reordered to this; the longest string is at index 5, the shortest one at index 0 of the presorted list.
5 3 1 0 2 4
We start with Enumerable.Range(0, length) yielding
0 1 2 3 4 5
then we apply i => length - 1 - 2 * i yielding
5 3 1 -1 -3 -5
and we have the non-negative part correct. Now note that i >> 31 is an arithmetic left shift and will copy the sign bit into all bits. Therefore non-negative numbers yield 0 while negative numbers yield -1. That in turn means subtracting i >> 31 will not change non-negative numbers but add 1 to negative numbers yielding
5 3 1 0 -2 -4
and now we finally apply Math.Abs() and get
5 3 1 0 2 4
which is the desired result. It works similarly for lists of odd length.
Just another option, which I find more readable and easy to follow:
You have an ordered list:
var strings = new List<string> {
"A",
"BB",
"CCC",
"DDDD",
"EEEEE",
"FFFFFF"};
Create a new list and simply alternate where you add items::
var new_list = new List<string>(); // This will hold your results
bool start = true; // Insert at head or tail
foreach (var s in strings)
{
if (start)
new_list.Insert(0,s);
else
new_list.Add(s);
start = !start; // Flip the insert location
}
Sweet and simple :)
As for Daniel Bruckner comment, if you care about which strings comes first, you could also change the start condition to:
// This will make sure the longest strings is first
bool start= strings.Count()%2 == 1;
I have to search a list of structs for every item whose XZPos is closer to Vector2 (or PointF) P. The list is ordered by XZPos' x and y. It'll look something like this:
Item 1 (XZPos: 0,0)Item 2 (XZPos: 0,1)Item 3 (XZPos: 0,2)...Item 12 (XZPos: 1,0)Item 13 (XZPos: 1,1)Item 14 (XZPos: 1,2)...2.249.984 elements later...
Now I have a point P (4,4) and I want a list of structs in the above list of every item closer to P than 5,66f. My algorithm searches every item in the list like this:
List<Node> res = new List<Node>();
for (int i = 0; i < Map.Length; i++)
{
Vector2 xzpos = new Vector2(Map[i].X, Map[i].Z);//Map is the list containing 2.250.000 elements
//neighbourlength = 5,66f in our example
if ((xzpos - pos).Length() <= neighbourlength && xzpos != pos)//looking for every item except the item which is P itself, therefore checking whether "xzpos != pos"
{
res.Add(new Node() { XZPos = xzpos, /*Other fields*/ });
}
}
return res.ToArray();
My problem is that it takes way too long to complete, and now I'm looking for a way to find the fields I'm looking for without searching the entire list. 22 seconds for a search is TOO LONG. If someone could help me get it to 1 or 2 seconds that would be very nice.
Thanks for your help, Alex
Your list is sorted, and you can use that to shrink the problem space. Instead of searching the whole list, search the subset of the list that spans x values within 5,66f, since anything that is farther than the maximum on one coordinate will be farther than you want no matter what the other coordinate is. Then if you store the start positions of each value in the list (i.e. in your example, "0" elements start at 1, and "1" elements start at 12), you can quickly get to the part of the list you care about. So instead of iterating through items 0 to 2 million, you could instead be iterating through items 175839 to 226835.
Example:
The List
1: (0,1)
2: (0,2)
3: (1,0)
4: (1,1)
5: (2,1)
6: (2,3)
7: (3,1)
8: (3,5)
9: (4,2)
10: (4,5)
11: (5,1)
12: (5,2)
13: (6,1)
14: (6,2)
15: (6,3)
16: (7,1)
17: (7,2)
Start Locations
(0,1)
(1,3)
(2,5)
(3,7)
(4,9)
(5,11)
(6,13)
(7,16)
If I have a point (3,5) and I want to search the list for points within 2 of it, I only need to iterate through the points where x is between 1 and 5. So I look at my start locations, and see that 1 starts at position 3 in the list, and 5 ends at position (13 - 1). So instead of iterating from 1 to 17, I only need to iterate from 3 to 12. If the range of values in your data is large but the distance to check is short, this will reduce the number of entries you need to iterate across greatly.
To the below solution there's a few assumptions. These assumptions are not stated in your question an the solution might need adjustment. If the assumptions hold this solution is extremely fast but requires you to keep the data in a different structure. However if you can change the structure then this will have a look of for each valid point in (almost) constant time. That is the time required to find M valid points in a set containing M point in total depends only on N.
The assumptions are:
Only positive integers are used for
values of X and Y
No duplicate points in the list
`private IEnumerable> GetPointsByDistance(int xOrigin, int yOrigin, double maxDistance){
var maxDist = (int) Math.Floor(maxDistance);
//Find the lowest possible value for X
var minX = Math.Min(0, xOrigin - maxDist);
//Find the highest possible value for X
var maxX = Math.Min(MaxX, xOrigin + maxDist);
for (var x = minX; x <= maxX; ++x){
//Get the possible values for Y with the current X
var ys = points[x];
if (ys.Length > 0){
//Calculate the max delta for Y
var maxYDist =(int)Math.Floor(Math.Sqrt(maxDistance*maxDistance - x*x));
//Find the lowest possible Y for the current X
var minY = Math.Min(0, yOrigin - maxYDist);
//Find the highest possible Y for the current X
var maxY = Math.Min(ys.Length, yOrigin + maxYDist);
for (var y = minY; y <= maxY; ++y){
//The value in the array will be true if a point with the combination (x,y,) exists
if (ys[y]){
yield return new KeyValuePair<int, int>(x, y);
}
}
}
}
}`
The internal representation of the point in this code is bool[][]. The value will be true if the indices of the two arrays is a point included in the set. E.g. points[0][1] will be true for if the set was the six points you've included in the post and points[0][3] would be false.
If the assumptions are not met the same idea can still be used but will need tweeking. If you post what the assumptions should be I'll update the answer to the question.
An assumption that does not have to be met is that the points are close to sequential. If they are not this will be rather greedy when it comes to memory. Changes can be made if the points are not (close) to sequential and again post the invariants if my assumptions are wrong and I'll update.
I have no idea what your original code is doing. I see you've defined x and y and never use them and you refer to pos but it's not defined. So, instead I'm going to take the verbal description of the problem your trying to solve
Now I have a point P (4,4) and I want a list of structs in the above list of every item closer to P than 5,66f.
and solve it. This is easy:
var nearbyNeighbors = Map.Where(
point => (point.X - 4) * (point.X - 4) +
(point.Z - 4) * (point.Z - 4) <
5.66f * 5.66f
);
foreach(var nearbyNeighbor in nearbyNeighbors) {
// do something with nearbyNeighbor
}
Here, I am assuming that you are using the standard Euclidean norm.
To utilize the fact that the collection is lexicographically sorted:
Binary search until |point.X - 4| >= 5.66. This splits the list in two contiguous sublists. Throw out the sublist with |point.X - 4| >= 5.66. From the remaining sublist, binary search until |point.Y - 4| >= 5.66 This splits the remaining sublist into two contiguous sublists. Throw out the sublist with |point.Y - 4| >= 5.66. Then search linearly through the remaining sublist.
This problem is related to this:
http://en.wikipedia.org/wiki/Nearest_neighbor_search
Take a look for sub-linear solutions.
Also take a look at this question
which data structure is appropriate to query "all points within distance d from point p"