How to add an item to a List<List<T>>? - c#

I think this is the right question / way to do this:
I have a list of coords (x,y) and an object (Location) which has X and Y; I, then, have a function where I check for each adjacent location and I compare them with my List items (which I converted to a jagged array)
static List<Location> GetWalkableAdjacentSquares(int x, int y, PointWithID [][]Map, Location target)
{
var proposedLocations = new List<Location>()
{
new Location { X = x, Y = y - 1 },
new Location { X = x, Y = y + 1 },
new Location { X = x - 1, Y = y },
new Location { X = x + 1, Y = y },
};
return proposedLocations.Where(l => Map[l.X][l.Y].value == 0).ToList();
}
(0 means it is open path)
Now, my List, is a simple List, and, therefore, I have an error:
public static List<PointWithID> map = new List<PointWithID>();
so I need to to the List this way (I guess):
public static List<List<PointWithID>> map = new List<List<PointWithID>>();
my question is:
How do I add the items to the List that way?
Of course regular way does not work:
private void addItemsToMap()
{
try
{
foreach (PointWithID open in NewMapToShow.openPath)
{
map.Add(open);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
Any help, please?

Well, given you have a List<List<PointWithID>> which is a list of lists, when you call the Add() method you should add the generic type which the list expects. So, a new list should be added in the Add method. On the other hand, the inner list should add objects of PointWithID.
I am not sure what you are trying to do, but see the code bellow:
private void addItemsToMap()
{
foreach (PointWithID open in NewMapToShow.openPath)
map.Add(new List<PointWithID> { open }); // create a new list for each point
}
Or
private void addItemsToMap()
{
// add all points in the main list as a new item (a list)
map.Add(new List<PointWithID>(NewMapToShow.openPath));
}

Related

How do I generate a rule for more than one option in Bogus?

I have a rule to select an option at random:
.RuleFor(c=>field, x=>x.PickRandom("Option1", "Option2", "Option3", "Option4"))
With a default value, I can alter the probability of one of the items. I would like to set the probabilities of all four items. Option1 would be picked 50% of the time, Option2 would be picked 30%, then 15% for Option3, and 5% for Option4.
I would like to use a WeightedRandom:
.RuleFor(c=>field, x=>PickWeightedRandom(valueArray, weightArray)
There is no such method as PickWeightedRandom, but WeightedRandom is a method in the Randomizer class. How do I get the WeightedRandom to work?
EDIT: Maybe an extension method?
The following seems to work:
void Main()
{
var items = new []{"kiwi", "orange", "cherry", "apple"};
var weights = new[]{0.1f, 0.1f, 0.2f, 0.6f};
var faveFaker = new Faker<Favorite>()
.RuleFor(x => x.Fruit, f => f.Random.WeightedRandom(items, weights));
faveFaker.Generate(10).Dump();
}
public class Favorite
{
public string Fruit {get;set;}
}
Of course, using C# extension methods are always an excellent way to extend Bogus to best suit your API needs:
void Main()
{
var faveFaker = new Faker<Favorite>()
.RuleFor(x => x.Fruit, f => f.WeightedRandom( ("kiwi", 0.1f), ("orange", 0.1f),
("cherry", 0.2f), ("apple", 0.6f)) );
faveFaker.Generate(10).Dump();
}
public class Favorite
{
public string Fruit {get;set;}
}
public static class MyExtensionsForBogus
{
public static T WeightedRandom<T>(this Faker f, params (T item, float weight)[] items)
{
var weights = items.Select(i => i.weight).ToArray();
var choices = items.Select(i => i.item).ToArray();
return f.Random.WeightedRandom(choices, weights);
}
}
One answer is to pick the random string somewhere else, then use the => operator to point to the result.
public static string PickAString(string[] items, float[] weights)
{
// hopefully all the weights will add up to 1. If not, this method may throw for array out of bounds.
// Also, it would be best if the number of items in each array is the same, to prevent out of bounds exception.
// generate a number from 0 to less than 1
double randomValue = random.NextDouble();
double weightSum = 0;
for (int i = 0; i < items.Length; i++)
{
weightSum += weights[i];
if (randomValue < weightSum)
return items[i];
}
return null; // if the weights don't add up.
}
.RuleFor(c => c.field, _ =>
{
return PickAString(values, weights);
})
This works, but it would be more elegant to add this to the library.

Two Dimensional Array farthest point search

I am trying to retrieve the farthest point in a collection, by comparing the distances from each point in the pointsToSearchFrom List to each other point in the pointCloudToSearchList. You can see a sample scenario from the attached image. I am still not an expert in navigating these data structures, and this algorithm exceeds my current knowledge of traversing two dimensional arrays.
Here is the code that I have until know. Any help would be great.
public static void Test(List<Point3d> pointsToSearchFrom, List<Point3d> pointCloudToSearch)
{
int rows = pointsToSearchFrom.Count;
int columns = pointCloudToSearch.Count;
double[,] arrayDistance = new double [rows, columns];
for (int i = 0; i < pointsToSearchFrom.Count; i++)
{
for (int j = 0; j < pointCloudToSearch.Count; j++)
{
arrayDistance[i, j] = (pointsToSearchFrom[i] - pointCloudToSearch[j]).magnitude;
}
}
}
You can use a two-d array for this, but you do not have to.
What you need is the MaxBy method which can be found here:
https://github.com/morelinq/MoreLINQ/blob/master/MoreLinq/MaxBy.cs
We begin by constructing a sequence of pairs:
var pairs = from first in pointsToSearchFrom
from second in pointCloudToSearch
select new { first, second };
Note that in C# 7 you would use a tuple, not an anonymous type here.
Now we have a sequence of all possible pairs. Use MaxBy to find the pair that maximizes the given quantity:
var maxPair = pairs.MaxBy(pair => (pair.first - pair.second).magnitude);
And now you're done:
Console.WriteLine($"{maxPair.first} --> {maxPair.second});
If you have a large collection of points -- like, thousands or millions -- then there are special techniques you have to use, because if there are thousands of points then there will be millions of pairs, and if there are millions of points there will be trillions of pairs. But if you just have a small handful, this technique works fine.
I didn't catch on at first that this was 3D. I used a class and list to store the 2 points and the distances between them. That way I could not only get the longest distance but the 2 points producing the distance.
public class Distances
{
public double Distance { get; set; }
public Point3D FromPoint { get; set; }
public Point3D ToPoint { get; set; }
public Distances(Point3D from, Point3D to)
{
FromPoint = from;
ToPoint = to;
Distance = (to - from).Length;
}
}
private void OP2()
{
List<Point3D> searchFrom = new List<Point3D>()
{
new Point3D(20,30,50),
new Point3D(10,50,10),
new Point3D(30,40,20),
new Point3D(60,30,10)
};
List<Point3D> searchCloud = new List<Point3D>()
{
new Point3D(60,70,80),
new Point3D(110,30,30),
new Point3D(80,110,55),
new Point3D(90,20,90)
};
List<Distances> resultDistances = new List<Distances>();
foreach (Point3D p1 in searchFrom)
{
foreach (Point3D p2 in searchCloud)
{
Distances d = new Distances(p1, p2);
resultDistances.Add(d);
}
}
//The following is just for testing purposes, skip to var longestDistance
List<Distances> distancesInOrder = resultDistances.OrderByDescending(i => i.Distance).ToList<Distances>();
foreach (Distances d in distancesInOrder)
{
Debug.Print($"From Point ({d.FromPoint.X}, {d.FromPoint.Y}, {d.FromPoint.Z}) To Point ({d.ToPoint.X}, {d.ToPoint.Y}, {d.ToPoint.Z}) Distance = {d.Distance}");
}
var longestDistance = resultDistances.OrderByDescending(i => i.Distance).FirstOrDefault();
//this gives you the longest distance and the two points
MessageBox.Show($"First Point ({longestDistance.FromPoint.X}, {longestDistance.FromPoint.Y}, {longestDistance.FromPoint.Z}) Cloud Point ({longestDistance.ToPoint.X}, {longestDistance.ToPoint.Y}, {longestDistance.FromPoint.Z}) Distance = {longestDistance.Distance}");
}

Recursive function overwriting output list

I was working on a class to find every combination of N lists. The combination algorithm seems to work flawlessly (when I step through it) but I am having trouble saving off my results. I want to store all the resulting arrays in another list to use later, but when I do the last array combination overwrites all the previous ones. Example input/outputs and my code are below. Does anyone have any ideas how I can fix this? (I've tried reference parameters and global lists with the same result).
/*
Input: A B C
X Y
Expected Output: A X
A Y
B X
B Y
C X
C Y
Actual Output: C Y
C Y
C Y
C Y
C Y
C Y
*/
public class Combination<T>{
private static void Combine(T[] res, int ix, List<List<T>> data, ref List<T[]> allCombos){
foreach (T v in data[ix]){
res[ix] = v;
if (ix >= data.Count - 1){
allCombos.Add(res);
}else{
Combine(res, ix + 1, data, ref allCombos);
}
}
}
public static List<T[]> Combine(List<List<T>> data){
List<T[]> allCombos = new List<T[]>();
Combine(new T[data.Count], 0, data, ref allCombos);
return allCombos;
}
}
The main problem here is that you only ever allocate a single T[] instance. Which you just add to your List<T[]> over and over.
Instead of this:
allCombos.Add(res);
You should try this:
allCombos.Add(res.ToArray());
That will create a new copy of the array each time as you add it to the list.
try this. I think this should work. I am not on terminal to test it.
public class Combination<T>
{
static T[] res;
private static void Combine(int ix, List<List<T>> data, ref List<T[]> allCombos)
{
foreach (T v in data[ix])
{
res[ix] = v;
if (ix >= data.Count - 1)
{
allCombos.Add(res);
}
else
{
Combine(res, ix + 1, data, ref allCombos);
}
}
}
public static List<T[]> Combine(List<List<T>> data)
{
List<T[]> allCombos = new List<T[]>();
res = new T[data.Count];
Combine(0, data, ref allCombos);
return allCombos;
}
}
The problem is that res argument is reused and overwritten in each iteration. Here is my solution for you.
using System;
using System.Linq;
using System.Collections.Generic;
....
private IEnumerable<T[]> Combine<T>(IEnumerable<T[]> data)
{
if (!data.Any())
yield break;
var head = data.First();
var tail = Combine(data.Skip(1));
foreach (var e in head)
{
var list = new T[] {e};
if (!tail.Any())
yield return list;
else
{
foreach (var t in tail)
{
yield return list.Concat(t).ToArray();
}
}
}
}
For the record, I had a similar issue, with a list of custom objects recently. What did it for me was basically creating a new object, using the object that used to get overwriten ("subTree") as the basis.
//Do this
TreeView newTree= new TreeView {
name = subTree.name,
children = subTree.children
};
actualTree.Add(newTree);
//Not this
actualTree.Add(subTree)
If I did not do that, I would have gotten the last "subTree" object everytime I tried to add a TreeView element to the "actualTree" List. The solution is to create a new object with the values that you need from other object whenever you have to add an element to your list, so that you are not always adding the same object.

Get the inner points which are on a straight line

The question I'm about to ask might seem a Geometry question at the first glance, but it actually can be solved by using LINQ, at least I hope so!
I have 5 points on a straight line two of them are at the ends of the line. How can I select the ones that are in the interior of the line (not at the end points) using LINQ?
public class Point
{
public double X;
public double Y;
}
var listOfPointsOnALine = new List<Point>
{
new Point { X = 2500, Y = 50 },
new Point { X = 2540, Y = 112.5 },
new Point { X = 2580, Y = 175 },
new Point { X = 2620, Y = 237.5 },
new Point { X = 2660, Y = 300 },
}
So using some LINQ on the list above should give me the list below:
innerPointsOnALine: {(2540, 112.5), (2580, 175), (2620, 237.5)}
The points are ordered in the original list
The points should be in the same order they appear in the original list (listOfPointsOnALine)
If I understand it correctly then I think you are looking for:
var newList = listOfPointsOnALine
.Skip(1)
.Take(listOfPointsOnALine.Count - 2)
.ToList();
You may have to check for length of list before doing this.

How do I convert an array of structs into an array of Point3D objects in C#?

I intend to form 3D mesh object.
The mesh object has an 3D point array of approx. 50.000 items.
Due to the number of 3D points, the array must be initialized on the heap.
The required code is, shortly, as follows:
class MyMesh
{
public MeshGeometry3D Mesh3D // Properties tanimlaniyor
{
get { return GetMesh3D(); }
}
public struct mystruct
{
public int m_i;
public int m_j;
public int m_k;
public mystruct(int i, int j, int k)
{
m_i = i;
m_j = j;
m_i = k;
}
}
private mystruct[] mypts =
{
new mystruct(20 , 7 , 7),
.
.
new mystruct(23 , 5 , 7)
};
}
Could you explain me how 3D Coordinates in mystruct above can be converted
into 3D coordinates of a System.Windows.Media.Media3D.Point3D structure.
Thanks in advance.
Öner YILMAZ
If you have an actual list of 50,000 mystruct objects, would it be better to just create them as Point3D structs in the first place?
Simply do a "Find & Replace" of:
new mystruct(
and replace it with
new Point3D(
Then, change:
private mystruct[] mypts =
to:
private Point3D[] mypts =
Are you looking for something like this...
List<Point3D> points = mypts.Select<mystruct, Point3D> (x =>
new Point3D(x.m_i, x.m_j, x.m_k))
.ToList();
Alternatively, you could expose an iterator that returned an IEnumerable like this...
public IEnumerable<Point3D> Points()
{
foreach(var point in mypts)
{
yield return new Point3D(point.m_i, point.m_j, point.m_k, );
}
}
[add validation/error handling code as appropriate]
If you need to retain your mystruct objects as well as enable Point3D functionality, you could use something like:
class MyMesh {
...
public Point3D[] ToPoint3D()
{
Point3D[] p3D = null; // or set it to an Empty Point3D array, if necessary
if (mpts.Length > 0)
{
p3D = new Point3D[mpts.Length]
for (int x = 0; x < mypts.Length; x++)
{
p3D[x].X = new Point3D(mypts[x].m_i;
p3D[x].Y = new Point3D(mypts[x].m_j;
p3D[x].Z = new Point3D(mypts[x].m_k;
}
}
return p3D;
}
...
}

Categories