I have a set of x,y coordinates (in meters) for an orchard. I'm trying to automatically group rows and to number the trees inside the groups (rows) from top to bottom (based on a definition of what top and bottom are). Unfortunately, I have not been able to come up with a solution. See below for a picture as well as a link to a dataset.
An example of a number for a tree would be:
5-1
5-2
where 5 is the row number and 1 and 2 are the number of the tree inside the row.
The distance between trees in a row is about 6 meters, and between the rows about 12 meters. Thus a row can be defined where the neighboring trees are less than 7 meters away using Euclidean distance. Organizing the data by y coordinates does not work as the rows are not straight lines.
To make things more complicated, the rows need to be in order from either left to right or right to left.
Is there an existing algorithm that I can use? If not, what can I do to make this work? Some direction will be appreciated!
Data:
https://drive.google.com/file/d/1csLM4IpP3tMF0fqQkql6gIANHngX9A3c/view?usp=sharing
Thanks for all your help. See below for my solution. It is very messy, but I'm sure the idea will come through:
public class Group
{
public int group;
public int row;
public double highestRelDistance;
public Group(int _group)
{
group = _group;
}
}
public class Tree
{
public string name;
public Group group = new Group(0);
public int orderInGroup;
public double x;
public double y;
public string type;
public double relDistance;
}
public static void FitTreesToLine(List<Tree> treesList, out double m, out double c)
{
double[] xdata = treesList.Select(x => x.x).ToArray();
double[] ydata = treesList.Select(x => x.y).ToArray();
Tuple<double, double> p = Fit.Line(xdata, ydata);
double a = p.Item1; // == 10; intercept
double b = p.Item2; // == 0.5; slope
m = b;
c = a;
}
public static double FindDistanceBetweenPointAndLine(double m, double c, double point_x, double point_y )
{
double line_start_x = point_x * 0.5;
double line_start_y = m * line_start_x + c;
double line_end_x = point_x * 1.5;
double line_end_y = m * line_end_x + c;
double distance = Math.Abs((line_end_x - line_start_x) * (line_start_y - point_y) - (line_start_x - point_x) * (line_end_y - line_start_y)) /
Math.Sqrt(Math.Pow(line_end_x - line_start_x, 2) + Math.Pow(line_end_y - line_start_y, 2));
return (distance);
}
public static void DoCalculations(List<Tree> treeList)
{
//Calculate groups
Group curGroup = new Group(1);
groupList.Add(curGroup);
int searchFailures = 0;
treeGrouping:
List<Tree> noGroupList = treeList.Where(x => x.group.group == 0).ToList();
List<Tree> closeTreeList = new List<Tree>();
if (noGroupList.Count() >= 3 && searchFailures < 1000)
{
var refTree = noGroupList[0];
closeTreeList.Add(refTree);
for (int i = 1; i < noGroupList.Count(); i++)
{
double distance = Math.Sqrt(Math.Pow(refTree.x - noGroupList[i].x, 2) + Math.Pow(refTree.y - noGroupList[i].y, 2));
if (distance <= 7)
{
closeTreeList.Add(noGroupList[i]);
if (closeTreeList.Count() == 2)
{
//Fit linear curve
double m = 0;
double c = 0;
FitTreesToLine(closeTreeList, out m, out c);
//Find all points that is close to the line in original tree list
for (int j = 0; j < noGroupList.Count(); j++)
{
double distanceFromLine = FindDistanceBetweenPointAndLine(m, c, noGroupList[j].x, noGroupList[j].y);
if (distanceFromLine <= 8)
{
noGroupList[j].group = curGroup;
}
}
//Iterate current group
curGroup = new Group(curGroup.group + 1);
groupList.Add(curGroup);
goto treeGrouping;
}
}
}
refTree.group.group = 9999999;
//curGroup = new Group(curGroup.group + 1);
//groupList.Add(curGroup);
searchFailures++;
goto treeGrouping;
}
//Order trees within their groups
foreach (var group in groupList)
{
var groupTreeList = treeList.Where(x => x.group == group).OrderBy(x => x.y).ToList();
for (int i = 0;i < groupTreeList.Count();i++)
{
groupTreeList[i].orderInGroup = i + 1;
}
}
//Get max group rel distance
foreach (var group in groupList)
{
var items = treeList.Where(x => x.group == group);
if (items.Count() > 0)
{
group.highestRelDistance = items.OrderBy(x=>x.orderInGroup).Last().x;
}
}
//Order tree groups into rows
groupList = groupList.OrderBy(x => x.highestRelDistance).ToList();
for (int i = 0;i < groupList.Count();i++)
{
var items = treeList.Where(x => x.group == groupList[i]).ToList();
foreach (var item in items)
{
item.group.row = i;
}
}
//Generate tree names
foreach (var tree in treeList)
{
tree.name = "(" + tree.group.row.ToString().PadLeft(2,'0') + "-" + tree.orderInGroup.ToString().PadLeft(3, '0') + ")";
}
//Order list
treeList = treeList.OrderBy(x => x.group.row).ThenBy(x => x.orderInGroup).ToList();
}
Related
I have trouble coming up with an algorithm for Knight Game task.
The description of the task is:
The knight game is played on a board with dimensions N x N and a lot of chess knights 0 <= K <= N².
I receive a board (char matrix) with 'K' for knights and '0' for empty cells. My task is to remove a minimum of the knights, so there will be no knights left that can attack another knight. On the first line, I receive the N size of the board. On the next N lines I receive strings with Ks and 0s.
This is what I devised so far:
public class SolutionTwo
{
public static void Main()
{
var size = int.Parse(Console.ReadLine());
var board = new char[size][];
PrepareBoard(board);
var knights = new List<Knight>();
for (int x = 0; x < board.Length; x++)
{
for (int y = 0; y < board[x].Length; y++)
{
if (board[x][y] == 'K')
{
knights.Add(new Knight()
{
X = x,
Y = y,
KnightAttacks = GetKnightAttacks(x, y, board)
});
}
}
}
var count = 0;
foreach (var knight in knights.OrderByDescending(k => k.KnightAttacks.Count()))
{
if (!IsReaminingHits(board))
{
break;
}
board[knight.X][knight.Y] = '0';
count++;
foreach (var subK in knight.KnightAttacks)
{
var c = knights.Single(k => k.X == subK.Item1 && k.Y == subK.Item2);
c.KnightAttacks.Remove(new Tuple<int, int>(knight.X, knight.Y));
}
// for test purposes
//Console.WriteLine($"Kn: [{knight.X} {knight.Y}] - he attacks: {string.Join(" ", knight.KnightAttacks)} {knight.KnightAttacks.Count()}");
}
Console.WriteLine(count);
}
private static bool IsReaminingHits(char[][] board)
{
for (int i = 0; i < board.Length; i++)
{
for (int j = 0; j < board[i].Length; j++)
{
if (board[i][j] == 'K')
{
if (GetKnightAttacks(i, j, board).Count > 0)
{
return true;
}
}
}
}
return false;
}
private static void PrepareBoard(char[][] board)
{
for (int i = 0; i < board.Length; i++)
{
board[i] = Console.ReadLine()
.ToCharArray();
}
}
private static List<Tuple<int, int>> GetKnightAttacks(int x, int y, char[][] board)
{
var deltas = new int[8][]
{
new int[] {-2, -1},
new int[] {-2, +1},
new int[] {+2, -1},
new int[] {+2, +1},
new int[] {-1, -2},
new int[] {-1, +2},
new int[] {+1, -2},
new int[] {+1, +2}
};
var xCandidate = 0;
var yCandidate = 0;
var list = new List<Tuple<int, int>>();
for (int i = 0; i < 8; i++)
{
xCandidate = x + deltas[i][0];
yCandidate = y + deltas[i][1];
if (0 <= xCandidate && xCandidate < board.Length
&& 0 <= yCandidate && yCandidate < board[0].Length
&& board[xCandidate][yCandidate] == 'K')
{
list.Add(new Tuple<int, int>(xCandidate, yCandidate));
}
}
return list;
}
}
public class Knight
{
public int X { get; set; }
public int Y { get; set; }
public List<Tuple<int, int>> KnightAttacks { get; set; } = new List<Tuple<int, int>>();
}
Example #1:
Input:
5
0K0K0
K000K
00K00
K000K
0K0K0
Expected result: 1
Example #2:
Input:
8
0K0KKK00
0K00KKKK
00K0000K
KKKKKK0K
K0K0000K
KK00000K
00K0K000
000K00KK
Expected result: 12
The algorithm is flawed, as can be seen more easily on this smaller board:
4
000K
0K00
00K0
K000
The solution here should be 2; but the algorithm returns 3. The reason for this is that the algorithm removes the first knight with the most attacks; assuming that this removal is part of the correct answer; however, there may be multiple knights with that number of attacks, and the first is not necessarily the best choice.
Also knights.OrderByDescending(k => k.KnightAttacks.Count()) doesn't do what you want it to do, even if you add knight.KnightAttacks.Clear(); inside the loop, since it has to evaluate all the values in order to enumerate them; but of course those numbers will vary as you start removing knights.
The correct algorithm is going to need to try all of the alternatives with the same number of attacks, to work out which is best. I can also come up with scenarios where the knight-with-the-most-attacks is not be the best choice. For example:
7
K00000K
00K0K00
KK000KK
0K0K0K0
0000000
0000000
0000000
So using the following replacement for the code beginning var count=0; improves the algorithm a little (e.g. it gets the correct answer of 2 for my small example, and 12 for "Example #2"); but isn't the full solution:
var count = 0;
while (knights.Any(k => k.KnightAttacks.Count > 0))
{
var knight = knights.OrderByDescending(k => k.KnightAttacks.Count).First();
// for test purposes
//Console.WriteLine($"Kn: [{knight.X} {knight.Y}] - he attacks: {string.Join(" ", knight.KnightAttacks)} {knight.KnightAttacks.Count()}");
board[knight.X][knight.Y] = '0';
count++;
foreach (var subK in knight.KnightAttacks)
{
var c = knights.Single(k => k.X == subK.Item1 && k.Y == subK.Item2);
c.KnightAttacks.Remove(new Tuple<int, int>(knight.X, knight.Y));
}
knight.KnightAttacks.Clear();
}
I'm attempting to create a turn based strategy game using a 3D HexGrid map, I've implemented dijkstra's algorithm but it doesn't run 100% efficiently and I can't work out why. I also attempted to implement A* but have had to stop as I can't work out how to properly implement it, so any help with that would also be massively appreciated.
My unit passes it's GameObject and the Vector3 of it's target to the generate path function and each Node in the graph list is populated with its x,y,z and all of it's neighbors.
The inefficiencies are such that when moving; in a -X direction when on an odd Z plane or in a +X when on an even Z plane, an extra step is made, shown in the screenshots. Another Inefficiency is that when moving in the Z plane an extra step is often taken as the code seems to prefer keeping it's X value the same for as long as possible before approaching on the Z plane. This is leading to the unit being 1 tile further from the goal when it starts it's Z movement than it would have been has it moved 1 X negatively to start with.
I'll add my path generation code, neighbor generation code and my node class code as well as screenshots of where the inefficiencies are occurring as I know my explanations are unclear at best. The neighbor code ensures that the highest adjacent tile is the one stored as the neighbor (it also has to search through types as i have a variety of tile types.
Thank you so much in advance, to anyone that might be able to offer some help or insight in to what is going wrong.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System;
using System.Linq;
public class UnitMasterScript : MonoBehaviour {
// private int Number_of_neighbours = 6;
private int Number_of_neighbours = 6;
private GameObject[] Neighbours;
Node[,,] graph;
public bool MapMakerDone = false;
void Update()
{
if (MapMakerDone == true)
{
// Wait for MapMaker to change MapMakerDone to true then allow rest of script to run
GameObject Map = GameObject.Find("MapMaker");
int WidthVal = Map.GetComponent<MapMakerFromFile>().WidthVal;
int HeightVal = Map.GetComponent<MapMakerFromFile>().HeightVal;
int DepthVal = Map.GetComponent<MapMakerFromFile>().DepthVal;
// Graph of node generation code
// Code to find which hex is to each side of this hex
// Need to find hex to left, right, ul, ur, ll, lr
// Need to find hex at the top of the stack adjacent
// 0:L 1:R 2:UL 3:UR 4:LL 5:LR
graph = new Node[WidthVal, HeightVal, DepthVal];
for (int x = 0; x < WidthVal; x++)
{
for (int y = 0; y < HeightVal; y++)
{
for (int z = 0; z < DepthVal; z++)
{
graph[x, y, z] = new Node();
graph[x, y, z].x = x;
graph[x, y, z].y = y;
graph[x, y, z].z = z;
}
}
}
for (int x = 0; x < WidthVal; x++)
{
for (int y = 0; y < HeightVal; y++)
{
for (int z = 0; z < DepthVal; z++)
{
// Set up the x and y for the neighbour as the source so it can be used
int neighbourX = x;
int neighbourY = 0; // must always start from 0 to ensure a downstep isn't missed
int neighbourZ = z;
int neighbourType = 0;
int correct_type = 0;
GameObject Hex_Present_checker = null;
// First needs to check if there even is a tile at this coordinate location
for (neighbourType = 0; neighbourType < 5; neighbourType++)
{
Hex_Present_checker = GameObject.Find("Hex_" + x + "_" + y + "_" + z + "_" + neighbourType);
if (Hex_Present_checker != null)
{
correct_type = neighbourType;
}
Hex_Present_checker = null;
}
if (correct_type != 0)
{
neighbourType = correct_type;
// int Number_of_neighbours = 6;
// GameObject[] Neighbours;
Neighbours = new GameObject[Number_of_neighbours];
// For each value of each tile in neighbours find what the tile coordinates are in XYZ
for (int q = 0; q < Number_of_neighbours; q++)
{
// Finds X and Z values of the neighbours
if (q < 2)
{
if (q == 0) { neighbourX = x + 1; }
if (q == 1) { neighbourX = x - 1; }
}
if (z % 2 == 1)
{
if (q == 2) { neighbourX = x; neighbourZ = z + 1; }
if (q == 3) { neighbourX = x + 1; neighbourZ = z + 1; }
if (q == 4) { neighbourX = x; neighbourZ = z - 1; }
if (q == 5) { neighbourX = x + 1; neighbourZ = z - 1; }
}
else
{
if (q == 2) { neighbourX = x - 1; neighbourZ = z + 1; }
if (q == 3) { neighbourX = x; neighbourZ = z + 1; }
if (q == 4) { neighbourX = x - 1; neighbourZ = z - 1; }
if (q == 5) { neighbourX = x; neighbourZ = z - 1; }
}
// Checks for the highest tile for the XZ coordinate and gets its Y value
GameObject potential_highest_ring;
int highest_Y = 0;
int correct_neighbour_type = 0;
for (neighbourY = 0; neighbourY < HeightVal; neighbourY++)
{
for (neighbourType = 0; neighbourType < 5; neighbourType++)
{
potential_highest_ring = null;
potential_highest_ring = GameObject.Find("Hex_" + neighbourX + "_" + neighbourY + "_" + neighbourZ + "_" + neighbourType);
if (potential_highest_ring != null)
{
highest_Y = neighbourY;
correct_neighbour_type = neighbourType;
}
}
}
// Need to check if there is a neighbour at the given coordinates
// Debug.Log("Hex_" + neighbourX + "_" + highest_Y + "_" + neighbourZ + "_" + neighbourType);
Neighbours[q] = GameObject.Find("Hex_" + neighbourX + "_" + highest_Y + "_" + neighbourZ + "_" + correct_neighbour_type);
// While there is a neighbour in the neighbours array
// add it's coordinates to the graph node as a part of its neighbours sublist
if (Neighbours[q] != null)
{
graph[x, y, z].neighbours.Add(graph[neighbourX, highest_Y, neighbourZ]);
}
}
}
}
}
}
MapMakerDone = false;
}
}
// List<Node> currentPath = null;
public List<Node> GeneratePathTo(GameObject SelectedUnit, Vector3 targetVec)
{
// Dijkstra's Algorithm Implementation
Dictionary<Node, float> dist = new Dictionary<Node, float>();
Dictionary<Node, Node> prev = new Dictionary<Node, Node>();
List<Node> unvisited = new List<Node>();
Node source = graph[
SelectedUnit.GetComponent<UnitBasicScript>().HexX,
SelectedUnit.GetComponent<UnitBasicScript>().HexY,
SelectedUnit.GetComponent<UnitBasicScript>().HexZ];
// TargetNode float to int conversion
int targetVecXInt = (int)targetVec.x;
int targetVecYInt = (int)targetVec.y;
int targetVecZInt = (int)targetVec.z;
Node targetNode = graph[
targetVecXInt,
targetVecYInt,
targetVecZInt];
// Debug.Log(targetVecXInt + "_" + targetVecYInt + "_" + targetVecZInt);
dist[source] = 0;
prev[source] = null;
// Initialise everything to have infinity distance since no other
information available
// Some nodes might not eb erachable therefore infinity is reasonable
foreach (Node v in graph)
{
if (v != source)
{
dist[v] = Mathf.Infinity;
prev[v] = null;
}
unvisited.Add(v);
}
while (unvisited.Count > 0)
{
// u is unvisited node with shortest distance
Node u = null;
foreach (Node possibleU in unvisited)
{
if (u == null || dist[possibleU] < dist[u])
{
u = possibleU;
}
}
unvisited.Remove(u);
if (u == targetNode)
{
break;
}
foreach (Node v in u.neighbours)
{
float alt = dist[u] + u.Distanceto(v);
if (alt < dist[v])
{
dist[v] = alt;
prev[v] = u;
}
}
}
if (prev[targetNode] == null)
{
// No route to target
return null;
}
List<Node> currentPath = new List<Node>();
Node curr = targetNode;
while (prev[curr] != null)
{
currentPath.Add(curr);
curr = prev[curr];
}
currentPath.Reverse();
return currentPath;
} // End of generate path function
public class Node
{
public int x = 0;
public int y = 0;
public int z = 0;
public List<Node> neighbours;
public Node()
{
neighbours = new List<Node>();
}
public float Distanceto(Node n)
{
if (n == null)
{
Debug.Log("Error");
}
return Vector2.Distance(
new Vector3(x, y, z),
new Vector3(n.x, n.y, n.z));
}
}
}
That concludes the code, I understand everything within monobehaviour has to be indented and it is in my code but upon copying into stackoverflow it lost that indentation. Next are the pictures showing the incorrect paths the units take.
https://imgur.com/a/wEChdq3
If any other information is needed please let me know and I will be more than happy to provide it. Thank you so much again!
You are using a List instead of a priority queue, which is massively inefficient. Also, since your grid has a simple heuristic, you should consider using A* which will be much faster.
Despite all the glaring inefficiencies which i still haven't resolved, I have resolved the problems with the algorithm implementation. I was getting the distance between the tile grid coordinates which didn't take into account that on a hex grid a diagonal movement has the exact same distance cost as a horizontal movement. Therefore the solution was to get the distance once the node grid coordinates had been converted to world coordinates as this will ensure all distances between adjacent tiles are equal.
Hope this helps if anyone gets stuck with the same problem!
This question already has answers here:
How do I check if a number is a palindrome?
(53 answers)
Closed 8 years ago.
I'm trying to multiply two numbers and then reverse the answer and then compare the original value with the reversed value to see if they are the same numbers. After I reverse the value how do I set it back to an int or a string so I can compare them?
int i = 0;
var x = Enumerable.Range(100,999);
var y = Enumerable.Range(100,999);
foreach (var xValue in x)
{
foreach (var yValue in y)
{
i = (xValue * yValue);
var t = i.ToString();
var tempt = t.Reverse();
var temp = new string(tempt);
if (i.ToString() == temp)
{
}
}
}
Like this perhaps? (One shouldn't really give away answers to projecteuler problems, but this is only problem 4, so what the heck)
public int SolveProblem004()
{
int result = 0;
for (int a = 999; a >= 100; --a) {
for (int b = 999; b >= a; --b) {
int product = a * b;
if (product <= result) break;
if (IsPalindromic(product)) { result = product; break; }
}
}
return result;
}
public static bool IsPalindromic(int i)
{
return i == Reverse(i);
}
public static int Reverse(int number)
{
if (number < 0) return -Reverse(-number);
if (number < 10) return number;
int reverse = 0;
while (number > 0) {
reverse = reverse * 10 + number % 10;
number /= 10;
}
return reverse;
}
int n; //given number
int left = n;
int rev = 0;
while(left>0)
{
r = left % 10; //take the last number
rev = rev * 10 + r; //add it to a new number to flip it
left = left / 10; //left = Math.floor(left / 10);
}
You can do it this way:
int i = 0;
var x = Enumerable.Range(100, 999);
var y = Enumerable.Range(100, 999);
foreach (var xValue in x)
{
foreach (var yValue in y)
{
i = (xValue * yValue);
char[] number = i.ToString().ToCharArray();
char[] reversedNumber = i.ToString().ToCharArray();
Array.Reverse(reversedNumber);
if (new string(number).Equals(new string(reversedNumber)))
{
}
}
}
It will enter inside if loop if number is the same as reversed number and will just pass by in oposite case.
I am trying to analyse some data using a C# app and need to calculate trend lines. I am aware that there are multiple types of trend line but for now I am trying to calculate exponential growth; I am going to be using it to predict future values. The equation I have been working off is
x(t) = x(0) * ((1+r)^t)
And this is the code that I have written to try and replicate the graph:
public void ExponentialBestFit(List<DateTime> xvalues, List<double> yvalues)
{
//Find the first value of y (The start value) and the first value of x (The start date)
xzero = Convert.ToDouble(xvalues[0].ToOADate());
yzero = yvalues[0];
if (yzero == 0)
yzero += 0.1;
//For every value of x (exluding the 1st value) find the r value
//
// | y | Where t = the time sinse the start time (time period)
//Equation for r = t root|-------| - 1 Where y = the current y value
// | y[0] | Where y[0] = the first y value #IMPROVMENT - Average 1st y value in range
//
double r = 0;
//c is a count of how many r values are added; it is not equal to the count of all the values
int c = 0;
for (int i = 1; i < xvalues.Count; i++)
{
r += Math.Pow(yvalues[i]/yzero, 1/(Convert.ToDouble(xvalues[i].ToOADate()) - xzero)) - 1;
c++;
}
r = r / c;
}
The data I am passing in is over a period of time however the increments in which the time increases are not the same. When I created a chart in excel they use a different formula
x(t) = x(0)*(e^kt)
I think however I have no idea where the k value is being generated from. The two lists that I am passing in are Date and Value and each row in each list corresponds to the same row in the other list. The question is - Is there a better way of creating the equation and variables and are the variables I am getting the most accurate it can be for my data?
This is the c# version of the javascript provided.
// Calculate Exponential Trendline / Growth
IEnumerable<double> Growth(IList<double> knownY, IList<double> knownX, IList<double> newX, bool useConst)
{
// Credits: Ilmari Karonen
// Default values for optional parameters:
if (knownY == null) return null;
if (knownX == null)
{
knownX = new List<double>();
for (var i = 0; i<=knownY.Count; i++)
knownX.Add(i);
}
if (newX == null)
{
newX = new List<double>();
for (var i = 0; i <= knownY.Count; i++)
newX.Add(i);
}
int n = knownY.Count;
double avg_x = 0.0;
double avg_y = 0.0;
double avg_xy = 0.0;
double avg_xx = 0.0;
double beta = 0.0;
double alpha = 0.0;
for (var i = 0; i < n; i++)
{
var x = knownX[i];
var y = Math.Log(knownY[i]);
avg_x += x;
avg_y += y;
avg_xy += x * y;
avg_xx += x * x;
}
avg_x /= n;
avg_y /= n;
avg_xy /= n;
avg_xx /= n;
// Compute linear regression coefficients:
if (useConst)
{
beta = (avg_xy - avg_x * avg_y) / (avg_xx - avg_x * avg_x);
alpha = avg_y - beta * avg_x;
}
else
{
beta = avg_xy / avg_xx;
alpha = 0.0;
}
// Compute and return result array:
return newX.Select(t => Math.Exp(alpha + beta*t)).ToList();
}
The following JavaScript code should help. I used it to implement Excel's GROWTH function. It's written in JavaScript, but porting it to C# should be very easy. Please note that most of it was written by someone else (credits in the code).
function GROWTH(known_y, known_x, new_x, use_const) {
// Credits: Ilmari Karonen
// Default values for optional parameters:
if (typeof(known_x) == 'undefined') {
known_x = [];
for (var i = 1; i <= known_y.length; i++) known_x.push(i);
}
if (typeof(new_x) == 'undefined') {
new_x = [];
for (var i = 1; i <= known_y.length; i++) new_x.push(i);
}
if (typeof(use_const) == 'undefined') use_const = true;
// Calculate sums over the data:
var n = known_y.length;
var avg_x = 0;
var avg_y = 0;
var avg_xy = 0;
var avg_xx = 0;
for (var i = 0; i < n; i++) {
var x = known_x[i];
var y = Math.log(known_y[i]);
avg_x += x;
avg_y += y;
avg_xy += x*y;
avg_xx += x*x;
}
avg_x /= n;
avg_y /= n;
avg_xy /= n;
avg_xx /= n;
// Compute linear regression coefficients:
if (use_const) {
var beta = (avg_xy - avg_x*avg_y) / (avg_xx - avg_x*avg_x);
var alpha = avg_y - beta*avg_x;
} else {
var beta = avg_xy / avg_xx;
var alpha = 0;
}
// Compute and return result array:
var new_y = [];
for (var i = 0; i < new_x.length; i++) {
new_y.push(Math.exp(alpha + beta * new_x[i]));
}
return new_y;
}
Since x(t)=x(0)*e^{kt}, we can take logarithms to get ln x(t)=ln x(0) + kt. This means that to find ln x(0) and k, you can find the least squares fit for the data {(t,ln x(t))}. This will tell you that ln x(t) = b + at, so that k=a and x(0)=e^b.
I've been working on an Access file editor in C#, and i've been trying to get a search feature added to my program. So far, I have the database file populate a 2D array, which i then use to populate a ListView box in another window. From this new window, I would like to be able to search each entry by Model Number. So far, i've managed to incorporate the Levenstein Algorithm, which seems to have much use. I can get the algorithm to assign the distance value between each entry and the search keyboard, and assign that value to another integer array. I can also sort the results in increasing order.
However, my current problem is that i'd would like to have the Model numbers sorted with the same respect to the distance values from the Levenstein Algorithm, so that the most relevant result becomes the first choice in the ListView box. Any ideas anyone??!?!
Here's what i've got so far:
private void OnSearch(object sender, System.EventArgs e)
{
string a;
string b;
int[] result = new int[1000];
int[] sorted = new int[1000];
for (int i = 0; i < rowC; i++)
{
a = PartNum[i]; // Array to search
b = SearchBox1.Text; // keyword to search with
if (GetDistance(a, b) == 0)
{
return;
}
result[i] = GetDistance(a, b); //add each distance result into array
}
int index;
int x;
for (int j = 1; j < rowC; j++) //quick insertion sort
{
index = result[j];
x = j;
while ((x > 0) && (result[x - 1] > index))
{
result[x] = result[x - 1];
x = x - 1;
}
result[x] = index;
}
}
public static int GetDistance(string s, string t)
{
if (String.IsNullOrEmpty(s) || String.IsNullOrEmpty(t))
{
MessageBox.Show("Please enter something to search!!");
return 0;
}
int n = s.Length;
int m = t.Length;
if (n == 0)
{
return m;
}
else if (m == 0)
{
return n;
}
int[] p = new int[n + 1];
int[] d = new int[n + 1];
int[] _d;
char t_j;
int cost;
for (int i = 0; i <= n; i++)
{
p[i] = i;
}
for (int j = 1; j <= m; j++)
{
t_j = t[j - 1];
d[0] = j;
for (int i = 1; i <= n; i++)
{
cost = (s[i - 1] == t_j) ? 0 : 1;
d[i] = Math.Min(Math.Min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
}
_d = p;
p = d;
d = _d;
}
return p[n];
}
Do you have LINQ available to you? If so:
var ordered = PartNum.OrderBy(x => GetDistance(x, SearchBox1.Text))
.ToList();
// Do whatever with the ordered list
Note that this has the disadvantage of not aborting early if you find an exact match, as well as not making the actual distances available - but it's not entirely clear how you're using the results anyway...
Another option would be:
var ordered = (from word in PartNum
let distance = GetDistance(word, SearchBox1.Text))
orderby distance
select new { word, distance }).ToList();
Then you've got the distance as well.
In order to sort your array by Levenstein distance you need to include the model numbers as part of your array so that, when you sort the array by Levenstein number, the model numbers will go along for the ride.
To do this, create a class representing each part:
public class Part
{
public string PartNumber;
public int LevensteinDistance;
}
and then create an array of Part:
Part[] parts;
You can then reference each element like so:
parts[n].LevensteinDistance
parts[n].PartNumber