I have a list with ~100k of integer pairs like these ones:
0, 12
0, 14
0, 1
0, 8
0, 2
0, 4
0, 3
1, 5
1, 11
1, 8
1, 2
2, 7
2, 9
2, 4
2, 5
2, 13
3, 12
3, 10
3, 4
3, 6
...
I need to sort them like
0, 1
0, 2
0, 3
0, 4
0, 8
0, 12
0, 14
1, 2
1, 5
1, 8
1, 11
2, 4
2, 5
2, 7
2, 9
2, 13
3, 4
3, 6
...
Currently I am doing:
myList.Sort(comparer);
when the comparer is defined as:
class EdgeIntersectComparer : IComparer<EdgeIntersect>
{
public int Compare(EdgeIntersect l1, EdgeIntersect l2)
{
if (l1.V1 < l2.V1)
return -1;
if (l1.V1 > l2.V1)
return 1;
if (l1.V2 < l2.V2)
return -1;
if (l1.V2 > l2.V2)
return 1;
return 0;
}
}
What can I do to improve execution speed? Is there any smarter approach to the problem?
Thanks.
EDIT:
Tested myList.OrderBy(e => e.V1).ThenBy(e => e.V2) and it's slower.
You had commented in a deleted post that V1 is already sorted.
In addition by V1 the list is already sorted.
I did a test using data already ordered by V1, but with V2 initialized with random numbers. I found this faster than your method:
myList = myList.GroupBy(x => x.V1).SelectMany(x => x.OrderBy(y => y.V2)).ToList();
This only works if V1 is already sorted.
Just as a possible option you coult try an Array instead of a List. (it depends on your context). If you can't:
Asuming:
public class Pair
{
public int First { get; private set; }
public int Second { get; private set; }
public Pair(int first, int second)
{
this.First = first;
this.Second = second;
}
}
And how the List is already ordered by the first item, maybe something like this? not sure if this will be faster:
public static List<Pair> FullOrderedList(List<Pair> SemiOrderedList)
{
List<Pair> FList = new List<Pair>();
List<Pair> demi = new List<Pair>();
int MaxNumber = SemiOrderedList.Count;
int compared = 0;
for (int i = 0; i < MaxNumber; i++)
{
int first = SemiOrderedList[i].First;
if (compared == first)
{
demi.Add(SemiOrderedList[i]);
}
else
{
compared++;
FList.AddRange(demi.OrderBy(x => x.Second));
demi.Clear();
}
}
return FList;
}
A small speed increase can be gained by optimizing your comparer:
if (l1.V1 == l2.V1)
{
if (l1.V2 > l2.V2) return 1;
else return -1;
}
else if (l1.V1 < l2.V1)
return -1;
else return 1;
max 2 statements to check, rather than your 4.
Related
I have an observation list and want to find consecutive alternating up and down values for a given count. For example when observation list is { 1, 3, 4, 2, 7, 5, 6, 8, 1, 2, 4} and given count for check is 4, method should return a list<list>> as {{3,4,2,7}, {2,7,5,6}}.
I already create method as below, but want to do this with linq or more efficent way.Could anybody help?
List<List<decimal>> GetinvalidObservationMatrix(List<decimal> observationList, int checkedCount)
{
List<List<decimal>> invalidObservationMatrix = new List<List<decimal>>();
while (observationList.Count >= checkedCount)
{
List<decimal> currentObservationList = observationList.Take(checkedCount).ToList();
bool isGreater = false;
bool isPreviousGreater = false;
for (int i = 1; i < checkedCount - 1; i++)
{
isPreviousGreater = isGreater;
if (currentObservationList[i] == currentObservationList[i - 1] || currentObservationList[i] == currentObservationList[i + 1])
{
break;
}
if (currentObservationList[i] > currentObservationList[i - 1])
{
isGreater = true;
}
else
{
isGreater = false;
}
if (i != 1 && isGreater == isPreviousGreater)
{
break;
}
if (isGreater)
{
if (currentObservationList[i + 1] >= currentObservationList[i])
{
break;
}
}
else
{
if (currentObservationList[i + 1] <= currentObservationList[i])
{
break;
}
}
if (i == checkedCount - 2)
{
invalidObservationMatrix.Add(currentObservationList);
}
}
observationList = observationList.Skip(1).ToList();
}
return invalidObservationMatrix;
}
Accepting that this does not actually answer the original question, this code will find all the alternating sequences.
void FindAlternativeSequences()
{
var observations = new List<int>() { 1, 3, 4, 2, 7, 5, 6, 8, 1, 2, 4 };
const int threshold = 4;
var consecutivePairs = observations.Skip(1).Zip(observations, (a, b) => Math.Sign(a - b)).Zip(GetAlternator(), (x, y) => x * y);
var runs = FindEqualRuns(consecutivePairs).Select(t => new Tuple<int, int>(t.Item1, t.Item2 + 1)).ToList();
}
public IEnumerable<int> GetAlternator()
{
int value = -1;
int sanity = Int32.MaxValue;
while (--sanity > 0)
{
value *= -1;
yield return value;
}
yield break;
}
public IEnumerable<Tuple<int,int>> FindEqualRuns(IEnumerable<int> enumerable)
{
int previousValue = 0;
int index = 0;
int startIndex = 0;
bool foundAnElement = false;
foreach ( var value in enumerable )
{
if (index == 0) previousValue = value;
foundAnElement = true;
if (!value.Equals(previousValue))
{
// This is a difference, return the previous run
yield return new Tuple<int, int>(startIndex, index - startIndex);
startIndex = index;
previousValue = value;
}
index++;
}
if (foundAnElement)
{
yield return new Tuple<int, int>(startIndex, index - startIndex);
}
yield break;
}
What it does
The code finds all alternating sequences of any length, starting with either an up-step or a down-step. It then populates the runs variable with tuples where Item1 is the index of the first element in the sequence, and Item2 is the length of the alternating sequence.
This runs variable can then be used to ask a wide range of questions about the data, such as deriving the answer to the original question. The runs output by itself does not return the alternating sequences, but identifies where and how long they are.
How it works
The bulk of the of the work is done in one line:
var consecutivePairs = observations.Skip(1).Zip(observations, (a, b) => Math.Sign(a - b)).Zip(GetAlternator(), (x, y) => x * y);
This zips together the observations along with observations-skip-1 to give pairs of consecutive values. These pairs are then subtracted and run through the Math.Sign() function to give +1, -1 or 0 for whether the first is greater, the second is greater, or if they are the same. This output has runs of +1 or -1 for increasing or decreasing sequences. It's also one element shorter than observations.
observations => { 1, 3, 4, 2, 7, 5, 6, 8, 1, 2, 4 }
Output from 1st .Zip() => { 1, 1, -1, 1, -1, 1, 1, -1, 1, 1 }
This result is then zipped and multiplied by an alternating +1, -1, +1, -1, ... sequence. This results in runs of +1 or -1 indicating consecutive alternating up-steps and down-steps.
observations => { 1, 3, 4, 2, 7, 5, 6, 8, 1, 2, 4 }
Output from 1st .Zip() => { 1, 1, -1, 1, -1, 1, 1, -1, 1, 1 }
Output from 2nd .Zip() => { 1, -1, -1, -1, -1, -1, 1, 1, 1, -1 }
The line var runs = FindEqualRuns(consecutivePairs).Select(t => new Tuple<int, int>(t.Item1, t.Item2 + 1)).ToList(); then uses another function to find all the consecutive runs or either +1, -1, or 0 in that set, giving the startIndex and count. Because this gives us runs against the pairs enumeration (which is one element shorter than the original observations), we do need to add 1 to each count. For example, if it finds a run of 3 elements in the pairs enumeration, this represents a run of 4 elements in observations.
The output in runs gives the detail on the start and length of all the alternating sequences in the data.
runs => { {0, 2}, {1, 6}, {6, 4}, {9, 2} }
So there is:
a sequence of length 2, starting at the 0th index => { 1, 3 }
a sequence of length 6, starting at the 1st index => { 3, 4, 2, 7, 5, 6 }
a sequence of length 4, starting at the 6th index => { 6, 8, 1, 2 }
a sequence of length 2, starting at the 9th index => { 2, 4 }
Hope this helps
How can I do this for example if I have 1, 2, 3, 4, 5, 6, 7 array and I am in 4th position (number 5) and if you have to move it to the right 4 positions you should be in position 1 (number 2). The same goes with negative numbers but you move to left. I guess there is a need of while(true) loop?
Lets assume i is the index and n is the size of the array.
For positive i the needed index = i%n
For negative i i%n returns negative residue, so the needed index is n+i%n
You can use
int index(int i, int n) {
return i%n < 0 ? n + (i%n) : i%n;
}
You can calculate your index like this:
var newIndex = (index + 4) % 7;
So the fourth position becomes (4+4) % 7 or 1.
Always clearer with named functions and followable code path instead of voodoo one liners that work
public void MyTest()
{
var testData = new[] { 1, 2, 3, 4, 5, 6, 7 };
Assert.AreEqual(2, TraverseCircularArray(testData, 5, 3));
Assert.AreEqual(6, TraverseCircularArray(testData, 2, -4));
}
private int TraverseCircularArray(int[] array, int currentIndex, int interval)
{
var i = array[currentIndex];
if (currentIndex + interval < 0)
i = array[array.Length + (interval + currentIndex)];
else if (currentIndex + interval >= array.Length)
i = array[currentIndex - interval - 1];
else
i = array[currentIndex + interval];
return i;
}
First of all i searched through the questions and I haven't found the thing I need , maybe it doesn't exist haha but i'll give it a shot.I am new to C# and I am coming from C++, got highschool experience.
In C++ I had Vector<int> T[]; so I could create a list with a size that it wasn't know; and make something like this and not wasting space; to be more exact
T[0][....];
T[1][...];
1 2 3 4 5
1 2 3
2 4 1 5
0 0 0 0 0 0
I am trying to do this in C# and It doesn't seem to work; I have tried this so far:
public class myints
{
public int x { get; set; }
}
public List<myints[]> T = new List<myints[]>();
T[i].Add(new myints() { x = i });
I wanna be able to add stuff and then use Count() in a for to see how many elemts I have in a T[i]. like T[i].size()... Is this possible?
the program says System.Array does not contain a definition for Add
This example creates a list with a number of sublists of varying length and should serve as a good starting point for what you want to do.
List<List<int>> mainlist = new List<List<int>>();
List<int> counter = new List<int>() { 5, 4, 7, 2 };
int j = 0;
// Fill sublists
foreach(int c in counter)
{
mainlist.Add(new List<int>(c));
for(int i = 0; i < c; i++ )
mainlist[j].Add(i);
j++;
}
You could also add initialized lists to the main list
List<List<int>> mainlist = new List<List<int>>();
mainlist.Add(new List<int>() { 1, 5, 7 });
mainlist.Add(new List<int>() { 0, 2, 4, 6, 8 });
mainlist.Add(new List<int>() { 0, 0, 0 });
Hello I want to take 6 items from a list with 5 items at all. And I want to start taking the items at a given position. My result should be saved in another list.
For example:
List_1 = 1, 2, 3, 4, 5
6 items needed
start at position 2 {= 3}
List_result = 3, 4, 5, 1, 2, 3
List_1 = 7, 13, 6, 9, 17
2 items needed
start at position 4 {= 17}
List_result = 17, 7
I already tried to loop through the list with for and foreach, but could not find a real solution. Any help is greatly appreciated!
Something like this will do the trick. I wrote it up quickly, so I'm sure you can make it nicer
private IEnumerable<int> DoSomething(IEnumerable<int> set, int start, int num) {
var taken = 0;
var curSet = set.Skip(start);
while (taken < num) {
foreach(var current in curSet)
{
if (taken == num)
yield break;
yield return current;
taken++;
}
curSet = set;
}
}
Use like this:
DoSomething(new int[] { 1,2,3,4,5}, 2, 6);
Yields:
3,4,5,1,2,3
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
Console.WriteLine("Hello World");
var data = new List<int>(5){1,2,3,4,5};
var result = new List<int>(5);
for(int i=0;i<5;i++)
{
result.Add(data[(i+2)%data.Count]);
}
for(int i=0;i<result.Count;i++)
{
Console.WriteLine(string.Format("{0}\n",result[i]));
}
}
}
You could use this extension:
public static IEnumerable<T> TakeSpinning<T>(this IEnumerable<T> source, int take, int position = 0)
{
// skip check for invalid input like negative take or position
int skip = position;
int taken = 0;
while (taken < take)
{
foreach (T element in source)
{
if (skip > 0)
{
skip--;
continue;
}
yield return element;
if (++taken == take) break;
}
}
}
Your samples:
var List_1 = new List<int> { 1, 2, 3, 4, 5 };
var List_Result = List_1.TakeSpinning(6, 2).ToList(); // 3,4,5,1,2,3
var List_2 = new List<int> { 7, 13, 6, 9, 17 };
var List_Result2 = List_2.TakeSpinning(2, 4).ToList(); // 17,7
simple,
public static IEnumerable<T> TakeLoop<T>(
this IEnumerable<T> source,
int count,
int start = 0)
{
if (start < 0)
{
throw new ArgumentOutOfRangeException("start");
}
if (count < 0)
{
throw new ArgumentOutOfRangeException("count");
}
using (var m = source.GetEnumerator())
{
for (var i = 0; i < count + start; i++)
{
if (!m.MoveNext())
{
if (i < start)
{
throw new ArgumentOutOfRangeException("start");
}
m.Reset();
m.MoveNext();
}
if (i >= start)
{
yield return m.Current;
}
}
}
}
to be used, like this,
var result1 = (new[] { 1, 2, 3, 4, 5 }).TakeLoop(6, 3);
or this,
var result2 = (new[] { 7, 13, 6, 9, 17 }).TakeLoop(2, 4);
its a simple iteration , you can use a simple loop to do this:
List list;// add values
int itemNeeded; //set item need
int startPostion; //set the start postion
for(int i=0;i<itemNeeded;i++){
add to newList the item at (startPosition++ % length of list)
}
I am looking for a way to get all combination of a list item.
what i thinking is to have a two dimention array, similary to a bit map
e.g bit[][] mybitmap;
for example if i have 4 item in my list "A, B, C, D"
i want my bitmap to be populate like this
A B C D
0, 0, 0, 1 --> D
0, 0, 1, 0 --> C
0, 0, 1, 1 --> C, D
0, 1, 0, 0 --> B
0, 1, 0, 1
0, 1, 1, 0
0, 1, 1, 1
1, 0, 0, 0
1, 0, 0, 1
1, 0, 1, 0
1, 0, 1, 1 --> A, C, D
1, 1, 0, 0
1, 1, 0, 1
1, 1, 1, 0
1, 1, 1, 1 --> A, B, C, D
but how can i write some C# code to populate my bit map?
(PS: my list might have items around 80 to 90, not 100 to 200, just confirmed)
Thanks
So... just count from 1 to 15 (=(2^n)-1), and write as binary, perhaps using shift operations.
This is sane for small numbers... but gets rather large quite quickly. For 64 items you can model in a long, but that is 18,446,744,073,709,551,615 combinations... hint: you are never, ever, ever going to loop that far.
For small cases:
int n = 4;
int max = 1 << n;
for (long val = 1; val < max; val++)
{
long mask = 1 << (n - 1);
for (int bit = 0; bit < n; bit++)
{
bool set = (val & mask) != 0;
Console.Write(set ? "1 " : "0 ");
mask >>= 1;
}
Console.WriteLine();
}
Agree with Marc Gravell. You cannot pretend to generate a list like the one you describe and then collect the elements you need.
I've been doing something similar, but I only needed a subset of all the combinations, so I was filtering my elements during the list generation process. This way, each recursive iteration (I was using F#) does not create the elements that I already know that will be discarded at the end.
With this approach I could perform variations of 200 elements and get the list of valid results (which I already knew it was going to be not so big...)
In case you are interested, the problem you are describing is a combinatory problem. There's a nice article in C# here
I believe you don't need to store all combinations in memory.
Just start from array with all zero bits (first combination). To get next combination just add 1 to last bit of previous combination (it is easily implementing operation). And so on.
Low memory usage, support of up to 2 billions of digits. :)
private void button1_Click(object sender, EventArgs e)
{
string[] items = {"A", "B", "C", "D"};
bool[] bits = new bool[items.Length];
for (int i = 0; i < bits.Length; i++)
{
bits[i] = false;
}
while (!bits.All(x => x))
{
listBox1.Items.Add(string.Join(", ", GetCombination(items, bits)));
AddBit(bits, bits.Length - 1);
}
}
public string[] GetCombination(string[] items, bool[] bits)
{
List<string> combination = new List<string>();
for (int i = 0; i < bits.Length; i++)
{
if (bits[i])
{
combination.Add(items[i]);
}
}
return combination.ToArray();
}
private void AddBit(bool[] bits, int pos)
{
if (pos < 0)
{
// overflow :)
return;
}
if (bits[pos])
{
bits[pos] = false;
AddBit(bits, pos - 1);
}
else
{
bits[pos] = true;
}
}