I want to translate all points in a List<T>. This works:
for (int i = 0; i <PolygonBase.Count; ++i)
{
PolygonBase[i] = PolygonBase[i] + MousePos;
}
But using List<T>.ForEach doesn't:
PolygonBase.ForEach(v => v += MousePos);
Ideas?
Your current code is simply re-assigning the local variable v to a new value - it doesn't refer back to the original value in the list. It's the equivalent of writing:
foreach(int v in PolygonBase)
{
v += MousePos;
}
To write back to the original value, use ConvertAll:
PolygonBase.ConvertAll(v => v += MousePos);
Related
I have a video clip which contains a bunch of Meta data (Mostly single line of strings), which in turn are linked to a specific frame. I managed to separate the speed data from each line of the Meta data and store it with in another list lc4_highest_speed_2
for (int h = 0; h < lc4_file_calculations.Count; h++)
{
string hold_variable = lc4_file_calculations[h].Replace("-", ",");
var mySplitResult2 = hold_variable.Split(',');
var speed = mySplitResult2[mySplitResult2.Length - 45];
lc4_highest_speed.Add(speed + ":" + h);
}
for (int f = 0; f < lc4_highest_speed.Count; f++)
{
string hoe3 = lc4_highest_speed[f];
var mySplitResult3 = hoe3.Split(':');
var speed2 = mySplitResult3[mySplitResult3.Length - 2];
var speed3 = mySplitResult3[mySplitResult3.Length - 1];
string speed_test = speed2.ToString();
lc4_highest_speed_2.Add(speed2 + " - " + speed3);
}
The new list holds data like this 012 - 82 the first part before the - is the speed and the other is the index number related to value from another string. I have tried things like concat, however it hasn’t worked. What would be the best way to get the highest speed the element before the - while also keeping the relation of the index number the number after the -.
Thank you
Try following :
string[] input = {
"012 - 82",
"012 - 83",
"012 - 84",
"012 - 85",
"012 - 86",
"012 - 87",
"13 - 102",
"13 - 103",
"13 - 104",
"13 - 105",
"13 - 106"
};
var output = input
.Select(x => x.Split(new char[] { '-' }))
.Select(x => new { speed = int.Parse(x.First()), index = int.Parse(x.Last()) })
.OrderByDescending(x => x.speed)
.GroupBy(x => x.speed)
.First()
.ToList();
A solution in O(n) time complexity return the higher speed value with its high index value.
int highestSpeed = 0;
int indexNumber = 0;
foreach (var item in lc4_highest_speed_2)
{
var values = item.Split('-');
if (values?.Count() == 2)
{
int.TryParse(values[0], out int parsedValue);
if (parsedValue > highestSpeed)
{
highestSpeed = parsedValue;
int.TryParse(values[1], out indexNumber);
continue;
}
int.TryParse(values[1], out int parsedIndex);
if (highestSpeed == parsedValue && parsedIndex > indexNumber) indexNumber = parsedIndex;
}
}
You can leverage a tuple to do this. Tuples automatically define an ordering based on their members that implement IComparable<T>. (Comparison is done in the order that the tuple's members are declared.)
Since an int implements IComparable<T> if we construct a tuple with the first element being the integer speed and the second the integer index, then the comparison operation generated for the tuple will be exactly what you need.
Thus you can solve this with a Linq expression that splits each row into the speed and index strings, parses those strings into ints and creates a tuple for each pair of speed and index. Then you can find the biggest using IEnumerable.Max():
var max = lc4_highest_speed_2.Select(item =>
{
var elements = item.Split("-");
return (speed: int.Parse(elements[0].Trim()), index: int.Parse(elements[1].Trim()));
}).Max();
Note that max is a tuple with an int first element called speed and an int second element called index.
Try it on .Net Fiddle
You can store all the speed value in the list of integer where you can find the mx value and using its index you then can find the relation between the speed and index value.
For the reference, I have created the small program. Hope you will understand
using System;
using System.Collections.Generic;
using System.Linq;
class HelloWorld {
static void Main() {
List<string> data = new List<string>();
List<int> intdata = new List<int>();
data.Add("012 - 82");
data.Add("013 - 102");
for(int i=0;i<data.Count;i++){
intdata.Add(Int16.Parse(data[i].Substring(0,data[i].IndexOf("-"))));
}
Console.WriteLine(intdata.Max());
}
}
Another way to do it:
var maxSpeed = lc4.Max(x => Convert.ToInt32(x.Split(' ')[0]));
var maxLine = lc4.FirstOrDefault(x => x.StartsWith($"{maxSpeed} "));
var maxIndex = Convert.ToInt32(maxLine.Split('-')[1].Substring(1));
or if you want all indices:
var maxSpeed = lc4.Max(x => Convert.ToInt32(x.Split(' ')[0]));
var maxLines = lc4.Where(x => x.StartsWith($"{maxSpeed} "));
var maxIndexes = maxLines.Select(x => Convert.ToInt32(x.Split('-')[1].Substring(1)));
Not sure I am asking this right or this even possible.
I feel to explain my question it is best to ask right in the code at the relevant places so please see my comments in the snippet below.
I wonder how to achieve this without building a new list of values for each I iteration. I feel this should not be necessary.
The bigger picture of this loop is to plot individual dimensions of 3D points to three new 2D plots of these. Hope that makes sense.
for (int i = 0; i < 3; i++) // 3 iterations (X,Y;Z)
{
// what here? how to make the data component of Vector3D a variable
for (int k = 0; k <= Points.Count - 1; k++)
{
Vector2D TL = new Vector2D();
TL.x = ((1 / (float)FrameCount.Sum()) * k);
TL.y = Points[k].x; // on i = 0 want Points[k].x
// on i = 1 want Points[k].y
// on i = 2 want Points[k].z
TimelinePoints.Add(TL); // just collect to a flat list for now
}
}
One option would be to have an array of extraction functions that you could apply to points. You can then use the LINQ Select overload that accepts a Func<TInput, int, TOutput> to generate a sequence of the values you want to add, and add it to TimeLinePoints that way.
// Possibly store this in a static variable somewhere
var extractors = new Func<Point, float>[] { p => p.x, p => p.y, p => p.z };
// Just do this once; store the result as a float for simplicity when dividing later.
float frameSum = FrameCount.Sum();
foreach (var extractor in extractors)
{
TimeLinePoints.AddRange(Points.Select((point, index) =>
new Vector2D(index / frameSum, extractor(point));
}
(You could go even further using SelectMany potentially, but that's where I'd start...)
A considerably more pedestrian approach compared to Jon Skeet's answer would be to modify the Point struct to include an indexer, assuming that is an option:
public struct Point
{
float x;
float y;
float z;
public float this[int index]
{
get
{
switch (index)
{
case 0:
return x;
case 1:
return y;
case 2:
return z;
default:
throw new IndexOutOfRangeException();
}
}
set
{
switch (index)
{
case 0:
x = value;
break;
case 1:
y = value;
break;
case 2:
z = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
}
}
Then you could assign the proper field according to the value of your loop counter, like so:
for (int k = 0; k < Points.Count; k++)
{
Vector2D TL = new Vector2D();
TL.x = ((1 / (float)FrameCount.Sum()) * k);
TL.y = Points[k][i];
TimelinePoints.Add(TL); // just collect to a flat list for now
}
The alternate way is to use Linq to archive this:
Points
//foreach point create 3 Vector2D with X, Y and Z coordinate
.SelectMany((p, index) => new []
{
new Vector2D(index / frameSum, p.X),
new Vector2D(index / frameSum, p.Y),
new Vector2D(index / frameSum, p.Z)
})
//unfurl IEnumerable<IEnumerable<Vector2D>> to IEnumerable<Vector2D>
.Select(v => v)
.ToList();
I'm using this code to build my 3d surface plot in each point, but I have a problem that I need to parametrize my function so t variable will be looped from 0 to T value, but I can't figure it out how can I do it inside the delegate?
edited the first block for more clarity:
/*this is code for building 3d surface plot, parameter delegate is counting Z
value in each (x, y) point.
x, y are axis variables. t is constant here*/
new ILPlotCube()
{
new ILSurface((x, y) => (float) (1/(x+y+t))
}
Resulting pseudocode is something like:
float functionValue = 0;
for (double t = 0; t < T; t + deltaT)
{
/*t is loop parameter here*/
functionValue += (float) (1/(x+y+t));
}
return functionValue;
If you don't need an Expression Tree, then it should be:
Func<float, float, float> func = (x, y) =>
{
float functionValue = 0;
for (double t = 0; t < T; t += deltaT)
{
/*t is loop parameter here*/
functionValue += (float)(1 / (x + y + t));
}
return functionValue;
};
Note that I had to change the t + deltaT adder of the for
From there you can
new ILSurface(func);
This is a statement lambda, because it uses { ... } code after the =>. See https://msdn.microsoft.com/library/bb397687.aspx statement lambdas
I used code converter to go from VB to C# and I get errors in c#. specifically, error on Item and on string.join(",", Flop.ToArray). Error says it doesn't contain a definition for item but it works in VB.
VB
Dim Flop As New List(Of String)
For x As Integer = 0 To Dataset9.Tables(0).Rows.Count - 1 'ROWS
Flop.Add(Dataset9.Tables(0).Rows(x).Item("Id"))
Next
strAllRoleNames = String.Join(",", Flop.ToArray)
C#
List<string> Flop = new List<string>();
for (int x = 0; x <= Dataset9.Tables[0].Rows.Count - 1; x++)
{
Flop.Add(Dataset9.Tables[0].Rows[x].Item["Id"]);
}
strAllRoleNames = string.Join(",", Flop.ToArray);
Try this:
List<string> Flop = new List<string>();
for (int x = 0; x <= Dataset9.Tables[0].Rows.Count - 1; x++)
{
Flop.Add(Dataset9.Tables[0].Rows[x]["Id"].ToString());
}
strAllRoleNames = string.Join(",", Flop.ToArray());
They three keys that were missing here
Accessing the item in a row, you need to use the C# default indexer as Item doesn't exist in C#
Since the cell in a row is an object and you want a string, need to explicitly call ToString
When calling ToArray, you need the () at the end in C#
try...
Flop.Add(Dataset9.Tables[0].Rows[x]["Id"].ToString());
ToArray is a method()
List<string> Flop = new List<string>();
for (int x = 0; x <= Dataset9.Tables[0].Rows.Count - 1; x++)
{
Flop.Add(Dataset9.Tables[0].Rows[x]["Id"]);
}
strAllRoleNames = string.Join(",", Flop.ToArray());
In a more concise way you can try below instead:
strAllRoleNames = string.Join(",", Dataset9.Tables[0].AsEnumerable()
.Select(C => Convert.ToString(C["Id"]))
.ToArray());
Try the below changes:
Dataset9.Tables[0].Rows[x].Item["Id"] => Dataset9.Tables[0].Rows[x]["Id"]
Flop.ToArray => Flop.ToArray()
I have the following method that sorts a list of binding source indices and puts their corresponding objects into an array. I have also tried using Array.Sort() and neither works, the code within the foreach loop never gets called. I have tested that the variable int[] indices is neither empty nor null.
internal void Foo(int[] indices)
{
var bar = new Object[indices.length];
int i = 0;
foreach (int index in indices.OrderBy(x => x))
{
// this block never gets called
bar[i] = BindingSource[index];
i++;
}
}
You can try this:
var bar = indices.OrderBy(x => x).Select(x => BindingSource[x]).ToArray();
But I think that your code should work though I think that you could improve it using a for-loop instead of a foreach.
internal void Foo(int[] indices)
{
var bar = new Object[indices.Length];
indices = indices.OrderBy(x => x);
for(int i = 0; i < indices.Length; i++)
bar[i] = BindingSource[indices[i]];
}
Another thing, you should get sure that the indices.Length doesn't equal 0 so I think that indices is empty.
PS : C# is case-sensitive so indices.length in your code should be indices.Length .
The issue is that OrderBy was not returning the sorted array, as I had assumed it did. The following is my solution.
internal void Foo(int[] indices)
{
var bar = new Object[indices.Length];
int i = 0;
indices = indices.OrderBy(x => x).ToArray();
foreach (int index in indices)
{
// now this block gets called
bar[i] = BindingSource[index];
i++;
}
}