Related
So, i have a set of integers in an list
public List<int> numbers = new List<int>() { 3, 7, 6, 9, 8, 10, 11 }
what i am wanting to do is change those numbers so they are ordered between 0 and 6, to set as siblingindexs.
and then would be changed to become
public List<int> newArrangedNumbers = new List<int>() {0, 2, 1, 4, 3, 5, 6}
But im really not sure how to do this... Anyone know?
P.S. i cant rearrange the numbers because then i would lose track of the game objects since the numbers themselves aren't actually in an array, but i have gameobjects in an array, and i find the "SortIndex" of each gameobject, which are the numbers from above, the order of the numbers in the array is actually the order of GameObjects in the array, which i need to keep the same.
Edit: i also cannot change them to float values because for some reason, when using SetSiblingIndex(int), you have to integers, you cant use floats
Edit 2: i am NOT trying to sort the numbers, i am trying to CONVERT the numbers from 3-11 into 0-6 in ORDER
From:
{3, 7, 6, 9, 8, 10, 11}
To:
{0, 2, 1, 4, 3, 5, 6}
Edit 3: Here is my script for testing
List<int> Indexs = new List<int>() { 4, 7, 56, 9, 65, 67, 8, 3, 6 };
var sorted = Indexs.Select((x, i) => new KeyValuePair<int, int>(x, i)).OrderBy(x => x.Key).ToList();
List<int> newArrangedNumbers = sorted.Select(x => x.Value).ToList();
for(int i = 0; i < newArrangedNumbers.Count; i++)
{
Debug.Log(Indexs[i] + " : " + newArrangedNumbers[i]);
}
When i only had 7 (0-6) indexs in the "Indexs" List it worked fine, but when i added any more, it started giving me the incorrect numbers
This is what it gives with this
Here is a good method to achieve your desired output from this stack form C# Sort list while also returning the original index positions?
The modified code for your solution is below.
//The original list
List<int> numbers = new List<int>() { 3, 7, 6, 9, 8, 10, 11 };
var sorted = numbers
.Select((x, i) => new KeyValuePair<int, int>(x, i))
.OrderBy(x => x.Key)
.ToList();
//The sorted list
List<int> numbersSorted = sorted.Select(x => x.Key).ToList();
//List of indexes sorted based on the list above
List<int> newArrangedNumbers = sorted.Select(x => x.Value).ToList();
Edit
Since you sort the list, but also retrieve the sorted indexes based on the list you just sorted, you aren't going to have any mixup with your game objects.
It sounds like you want to find positions of each element in a sorted list of the same items.
So sort and find where element is and assign the index. Code sample below assumes unique numbers:
var sorted = numbers.OrderBy(x=>x).ToArray();
var result = new int[numbers.Count];
for (var i = 0; i < numbers.Count; i++)
{
var index = number.IndexOf(sorted[i]);
result[index] = i;
}
Notes
for anything about 5-10 items I'd use dictionary instead of IndexOf if you want to stick with this code.
if numbers are not unique or performance is critical you need to use solution by Aaron Jones that eventually will track original indexes even if it is harder to understand.
Every search I make assumes "Distinct()", but this is NOT my requirement. I just wish to remove all the repeats. Are there any options using linq (i.e. the Enumerable extensions) ?
For example (in C#)
int[] input = new [] {1,2,3,3,4,5,5,5,6,6,5,4,4,3,2,1,6};
int[] expected = new [] {1,2,3,4,5,6,5,4,3,2,1,6};
You are asking for non-repeating elements, not unique elements. LINQ-to-Objects operations are essentially iterators. You could write your own iterator method that only yields the first time an item is encountered, eg:
public static IEnumerable<int> DistinctUntilChanged(this IEnumerable<int> source)
{
int? previous=null;
foreach(var item in source)
{
if (item!=previous)
{
previous=item;
yield return item;
}
}
}
var input = new [] {1,2,3,3,4,5,5,5,6,6,5,4,4,3,2,1,6};
var result=input.DistinctUntilChanged().ToArray();
The result will be :
{1,2,3,4,5,6,5,4,3,2,1,6};
UPDATE
Another option is to use Observable.DistinctUntilChanged from the System.Reactive Library, eg:
var input = new[] { 1, 2, 3, 3, 4, 5, 5, 5, 6, 6, 5, 4, 4, 3, 2, 1, 6 };
var result = input.ToObservable()
.DistinctUntilChanged()
.ToEnumerable()
.ToArray();
System.Reactive, and Reactive Extensions are meant to handle sequences of events using the basic LINQ operators and more. It's easy to convert between Observable and Enumerable though, with ToObservable() and ToEnumerable(), so they can be used to handle any collection. After all, an event sequence is similar to an "infinite" sequence
UPDATE 2
In case there's any confusion about the use of int? to store the previous number, it's to allow easy comparison even with the first element of the source without actually calling First() on it. If it was ,eg int previous=0; and the first element was 0, the comparison would filter out the first element.
By using an int? in C# or an int option in F# or a Maybe<int> if we have a Maybe monad we can differentiate between no initial value and an initial value of 0.
Observable.DistinctUntilChanged uses a flag to check whether we are checking the first element. The equivalent code would be:
public static IEnumerable<int> NonRepeating(this IEnumerable<int> source)
{
int previous =0;
bool isAssigned=false;
foreach (var item in source)
{
if (!isAssigned || item != previous)
{
isAssigned = true;
previous = item;
yield return item;
}
}
}
MoreLINQ
Finally, one can use the GroupAdjacent method from the MoreLinq library to group repeating items together. Each group contains the repeating source elements. In this particular case though we only need the key values:
var result = input.GroupAdjacent(i => i).Select(i => i.Key).ToArray();
The nice thing about GroupAdjacent is that the elements can be transformed while grouping, eg :
input.GroupAdjacent(i => i,i=>$"Number {i}")
would return groupings of strings.
It is possible with linq, although for performance and readability a simple for loop would probably be the better option.
int[] input = new[] { 1, 2, 3, 3, 4, 5, 5, 5, 6, 6, 5, 4, 4, 3, 2, 1, 6 };
var result = input.Where((x, i) => i == 0 || x != input[i - 1]).ToArray();
I'm hoping this will be fairly simple and down to my lack of knowledge as a beginner but I'm trying to see if an array of ints with two elements is in a List.
Int[] meh = {1,2};
List<int[]> list1 = new List<int[]>();
List1.Add(meh);
Int[] meh2 = {1,2};
If(List1.Contains(meh2))
{
Console.WriteLine(“Found it”);
}
From reading around I gather that the array wont be found as it's to do with how Lists compare objects by reference and not value ... all examples Ive found have been to find a single int within an array in a List but not the array as a whole.
Im vaguely aware that List.Find() may be useful here but again I cant see how to use LINQ for matching both elements in each array in the list.
Any help or pointers to reading material greatly appreciated.
Thanks in advance.
How about this
if(list1.Any(x => x.SequenceEqual(meh2)))
{
Console.WriteLine("Found it");
}
You can use Enumerable.SequenceEqual
that will return -1 if the sequence is not found
example:
var myArr = new int[] { 3, 3 };
List<int[]> ListOfArrays = new List<int[]>
{
new int[] { 0, 0 },
new int[] { 2, 2 },
new int[] { 1, 1 },
new int[] { 3, 3 }
};
var index = ListOfArrays.FindIndex(l => Enumerable.SequenceEqual(myArr, l));
Console.WriteLine("here: " + index);
Not sure what you want to achieve exactly. If list1 has an element [1, 2, 3] and you search for [1, 2], would that be a match, or do all elements have to match? Do they have to be in the same order? ...
Whatever you want to achieve exactly, you can do it with Any() and SequenceEqual()
int[] meh = {1, 2};
int[] meh2 = {1, 5};
var list1 = new List<int[]>() {meh, meh2};
if (list1.Any(x => x.SequenceEqual(new[] {1, 5})))
{
Console.WriteLine("Found it");
}
Also see this answer. It contains an example where both arrays are sorted first (ie ignoring the order of the elements in the array)
How can we delete all array elements between 2 numbers?
For example : The array is {2,6,3,6,8,2,7,2}
The user writes in two numbers, let's say 2 and 4.
That causes the program to delete every array elements between the 2nd and 4th position.
In this case, it deletes : 3,6,8
You cannot delete items from an array. But you can create a new array that contains only the items that you want to keep. In your case you can use the following:
int[] array = {2, 6, 3, 6, 8, 2, 7, 2};
array = array.Where((_, i) => i < 2 || i > 4).ToArray();
By the way, if you use a List instead of an array, then you can remove items. Consider the following example:
List<int> list = new List<int>() {2, 6, 3, 6, 8, 2, 7, 2};
for(int i = 4; i >= 2 ; i--)
{
list.RemoveAt(i);
}
For lists, you can use RemoveRange to do exactly that. It’s just that instead of the (inclusive) end index, you need to pass the number of elements you want to delete. So for inclusive indexes start and end it would look like this:
list.RemoveRange(start, end - start + 1);
For arrays, you cannot really do this as once created arrays have a fixed size. If you really need an array, you could create a list from the array, remove the items, and then create an array again using ToArray.
As Yacoub Massad mentioned in his answer: You cannot delete items from an array. But you can create a new array that contains only the items that you want to keep. In this case I would use linq, it's super easy:
int[] array = {2, 6, 3, 6, 8, 2, 7, 2};
int x = 2;
int y = 4;
var array1 = array.ToList()
.Take(x).Concat(array.ToList().Skip(x+y-1))
.ToArray();
foreach(var i in array1)
{
Console.Write(i);
Console.Write(',');
}
Result:
2,6,2,7,2,
DotNetFiddle Example
I have two List's which I want to check for corresponding numbers.
for example
List<int> a = new List<int>(){1, 2, 3, 4, 5};
List<int> b = new List<int>() {0, 4, 8, 12};
Should give the result 4.
Is there an easy way to do this without too much looping through the lists?
I'm on 3.0 for the project where I need this so no Linq.
You can use the .net 3.5 .Intersect() extension method:-
List<int> a = new List<int>() { 1, 2, 3, 4, 5 };
List<int> b = new List<int>() { 0, 4, 8, 12 };
List<int> common = a.Intersect(b).ToList();
Jeff Richter's excellent PowerCollections has Set with Intersections. Works all the way back to .NET 2.0.
http://www.codeplex.com/PowerCollections
Set<int> set1 = new Set<int>(new[]{1,2,3,4,5});
Set<int> set2 = new Set<int>(new[]{0,4,8,12});
Set<int> set3 = set1.Intersection(set2);
You could do it the way that LINQ does it, effectively - with a set. Now before 3.5 we haven't got a proper set type, so you'd need to use a Dictionary<int,int> or something like that:
Create a Dictionary<int, int> and populate it from list a using the element as both the key and the value for the entry. (The value in the entry really doesn't matter at all.)
Create a new list for the intersections (or write this as an iterator block, whatever).
Iterate through list b, and check with dictionary.ContainsKey: if it does, add an entry to the list or yield it.
That should be O(N+M) (i.e. linear in both list sizes)
Note that that will give you repeated entries if list b contains duplicates. If you wanted to avoid that, you could always change the value of the dictionary entry when you first see it in list b.
You can sort the second list and loop through the first one and for each value do a binary search on the second one.
If both lists are sorted, you can easily do this in O(n) time by doing a modified merge from merge-sort, simply "remove"(step a counter past) the lower of the two leading numbers, if they are ever equal, save that number to the result list and "remove" both of them. it takes less than n(1) + n(2) steps. This is of course assuming they are sorted. But sorting of integer arrays isn't exactly expensive O(n log(n))... I think. If you'd like I can throw together some code on how to do this, but the idea is pretty simple.
Tested on 3.0
List<int> a = new List<int>() { 1, 2, 3, 4, 5, 12, 13 };
List<int> b = new List<int>() { 0, 4, 8, 12 };
List<int> intersection = new List<int>();
Dictionary<int, int> dictionary = new Dictionary<int, int>();
a.ForEach(x => { if(!dictionary.ContainsKey(x))dictionary.Add(x, 0); });
b.ForEach(x => { if(dictionary.ContainsKey(x)) dictionary[x]++; });
foreach(var item in dictionary)
{
if(item.Value > 0)
intersection.Add(item.Key);
}
In comment to question author said that there will be
Max 15 in the first list and 20 in the
second list
In this case I wouldn't bother with optimizations and use List.Contains.
For larger lists hash can be used to take advantage of O(1) lookup that leads to O(N+M) algorithm as Jon noted.
Hash requires additional space. To reduce memory usage we should hash shortest list.
List<int> a = new List<int>() { 1, 2, 3, 4, 5 };
List<int> b = new List<int>() { 0, 4, 8, 12 };
List<int> shortestList;
List<int> longestList;
if (a.Count > b.Count)
{
shortestList = b;
longestList = a;
}
else
{
shortestList = a;
longestList = b;
}
Dictionary<int, bool> dict = new Dictionary<int, bool>();
shortestList.ForEach(x => dict.Add(x, true));
foreach (int i in longestList)
{
if (dict.ContainsKey(i))
{
Console.WriteLine(i);
}
}
var c = a.Intersect(b);
This only works in 3.5 saw your requirement my apologies.
The method recommended by ocdecio is a good one if you're going to implement it from scratch. Looking at the time complexity compared to the nieve method we see:
Sort/binary search method:
T ~= O(n log n) + O(n) * O(log n) ~= O(n log n)
Looping through both lists (nieve method):
T ~= O(n) * O(n) ~= O(n ^ 2)
There may be a quicker method, but I am not aware of it. Hopefully that should justify choosing his method.
(Previous answer - changed IndexOf to Contains, as IndexOf casts to an array first)
Seeing as it's two small lists the code below should be fine. Not sure if there's a library with an intersection method like Java has (although List isn't a set so it wouldn't work), I know as someone pointed out the PowerCollection library has one.
List<int> a = new List<int>() {1, 2, 3, 4, 5};
List<int> b = new List<int>() {0, 4, 8, 12};
List<int> result = new List<int>();
for (int i=0;i < a.Count;i++)
{
if (b.Contains(a[i]))
result.Add(a[i]);
}
foreach (int i in result)
Console.WriteLine(i);
Update 2: HashSet was a dumb answer as it's 3.5 not 3.0
Update: HashSet seems like the obvious answer:
// Method 2 - HashSet from System.Core
HashSet<int> aSet = new HashSet<int>(a);
HashSet<int> bSet = new HashSet<int>(b);
aSet.IntersectWith(bSet);
foreach (int i in aSet)
Console.WriteLine(i);
Here is a method that removed duplicate strings. Change this to accomidate int and it will work fine.
public List<string> removeDuplicates(List<string> inputList)
{
Dictionary<string, int> uniqueStore = new Dictionary<string, int>();
List<string> finalList = new List<string>();
foreach (string currValue in inputList)
{
if (!uniqueStore.ContainsKey(currValue))
{
uniqueStore.Add(currValue, 0);
finalList.Add(currValue);
}
}
return finalList;
}
Update: Sorry, I am actually combining the lists and then removing duplicates. I am passing the combined list to this method. Not exactly what you are looking for.
Wow. The answers thus far look very complicated. Why not just use :
List<int> a = new List<int>() { 1, 2, 3, 4, 5, 12, 13 };
List<int> b = new List<int>() { 0, 4, 8, 12 };
...
public List<int> Dups(List<int> a, List<int> b)
{
List<int> ret = new List<int>();
foreach (int x in b)
{
if (a.Contains(x))
{
ret.add(x);
}
}
return ret;
}
This seems much more straight-forward to me... unless I've missed part of the question. Which is entirely possible.