Getting the longest string using properties - c#

I have following code:
public string Longest
{
get
{
int min = int.MinValue;
string longest = "";
for (Node i = Head; i != null; i = i.Next)
{
if (i.Text.Length > min)
{
longest = i.Text.Length.ToString();
}
return longest;
}
return longest;
}
}
The problem is I have those strings:
List text = new List();
text.Add("Petar");
text.Add("AHS");
text.Add("Google");
text.Add("Me");
When I try out the propertie it says that the longest string is 5 but thats not true the longest string is six. I've tried to find out where my problem but i coulnd't find it.

Your code has a couple of problems:
A length can be, as minimum, 0, so you don't need to use int.MinValue
You are returning on the first iteration
You are not updating min after finding a longer value
You are returning the length of the string, not the string itself
Your code should look like this:
public string Longest
{
get
{
int longestLength = 0;
string longestWord = string.Empty;
for (Node i = Head; i != null; i = i.Next)
{
if (i.Text.Length > longestLength)
{
longestLength = i.Text.Length;
longestWord = i.Text;
}
}
return longestWord;
}
}
If what you want to return is the maximum length instead of the word with the maximum length, your property is both wrongly named and typed, and it should look like this instead:
public int MaximumLength
{
get
{
int maximumLength = 0;
for (Node i = Head; i != null; i = i.Next)
{
if (i.Text.Length > maximumLength)
{
maximumLength = i.Text.Length;
}
}
return maximumLength;
}
}

If you have an IEnumerable<string> then do the following
var list = new List<string>();
list.Add("AAA");
list.Add("AAAAA");
list.Add("A");
list.Add("AAAA");
list.Add("AAAAAA");
list.Add("AA");
// max has the longest string
var max = list.Aggregate(string.Empty,
(bookmark, item) => item.Length>bookmark.Length ? item : bookmark);
or using a loop
string max = string.Empty;
int length=0;
foreach(var item in list)
{
if(item.Length>length)
{
max = item;
length = item.Length;
}
}
But it appears you have a linked list which I recreated as a skeleton below:
public class Node
{
public Node(string text)
{
this.Text = text;
this.Head = this;
}
public Node(Node parent, string text): this(text)
{
if(parent!=null)
{
parent.Next = this;
this.Head = parent.Head;
}
}
public Node Head { get; }
public Node Next { get; set; }
public string Text { get; }
public Node Add(string text) => new Node(this, text);
}
and finding the longest string with a loop is
var list = new Node("AAA");
list = list.Add("AAAAA");
list = list.Add("A");
list = list.Add("AAAA");
list = list.Add("AAAAAA");
list = list.Add("AA");
string max = list.Text;
int length = max.Length;
for(Node node = list.Head; node != null; node = node.Next)
{
if(node.Text.Length > length)
{
max = node.Text;
length= node.Text.Length;
}
}
// max has the longest string
Edit 1
I took the linked list and made it IEnumerable<string> by moving your loop code into a method:
public class Node : IEnumerable<string>
{
public Node(string text)
{
this.Text = text;
this.Head = this;
}
public Node(Node parent, string text) : this(text)
{
if(parent!=null)
{
parent.Next = this;
this.Head = parent.Head;
}
}
public Node Head { get; }
public Node Next { get; set; }
public string Text { get; }
public Node Add(string text) => new Node(this, text);
public IEnumerator<string> GetEnumerator()
{
// Loop through the list, starting from head to end
for(Node node = Head; node != null; node = node.Next)
{
yield return node.Text;
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
and now I can use a single LINQ statement
var list = new Node("AAA");
list = list.Add("AAAAA");
list = list.Add("A");
list = list.Add("AAAA");
list = list.Add("AAAAAA");
list = list.Add("AA");
// max has the longest string
var max = list.Aggregate(string.Empty,
(bookmark, item) => item.Length>bookmark.Length ? item : bookmark);

Related

Find the largest sum from top to bottom in a depth tree

I am looking to create a depth tree where each number is connected to two numbers on its left and right on the row below it.
Likewise, each number will be linked to the two numbers on its left and right on the row above it, or just one if it is at an end of its row.
Then I have to calculate the largest sum from top to bottom.
The numbers need to be added dynamically (by a text file) so I cannot add them individually. The format of the text file will look like the image below, taking carriage returns and spaces into consideration. The tree needs to look like this:
I tried to do this a few different ways but I cannot seem to find the best way to do it. I tried 2 dimensional arrays and node trees but I am not proficient enough to do them. Below is a snippet of my Node Tree code that I tried. Please let me know if I need to do anything else here.
public class Node
{
public int value;
public Node left;
public Node right;
public Node parent;
public Node(int value)
{
this.value = value;
}
}
public static Node NewNode(int value)
{
Node node = new Node(value);
node.left = null;
node.right = null;
node.parent = null;
return node;
}
public static void Insert(Node root, Node newNode)
{
if (root == null)
{
root = newNode;
}
else
{
if (root.left == null)
{
root.left = newNode;
newNode.parent = root;
}
else if(root.right == null)
{
root.right = newNode;
newNode.parent = root;
}
else
{
if (root.left.left == null)
{
Insert(root.left, newNode);
}
else
{
Insert(root.right, newNode);
}
}
}
}
public static Node GetTree(string filePath)
{
Node rootNode = null;
string[] lines = File.ReadAllLines(filePath);
if (lines.Length == 0) return null;
foreach (string line in lines)
{
if (string.IsNullOrWhiteSpace(line)) return null;
string[] values = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (values.Length == 0) return null;
foreach (string value in values)
{
int number;
if (!int.TryParse(value, out number)) return null;
}
if (rootNode == null)
{
rootNode = NewNode(int.Parse(values[0]));
}
else
{
Node node = rootNode;
foreach (string value in values)
{
Node newNode = NewNode(int.Parse(value));
Insert(node, newNode);
node = newNode;
}
}
}
return rootNode;
}
Edit: The text file will look similar to this, expecting to have spaces and carriage returns:
3
7 6
2 4 9
1 4 8 2
Structure of Graph.txt (Number of node, Weight of node, left number node, right number node):
(1,3,2,3)
(2,7,4,5)
(3,6,5,6)
(4,2,7,8)
(5,4,8,9)
(6,9,9,10)
(7,1,,)
(8,4,,)
(9,8,,)
(10,2,,)
Code:
public class Node
{
public int Id { get; set; }
public int Weight { get; set; }
public string LeftId { get; set; }
public string RightId { get; set; }
public Node Left { get; set; }
public Node Right { get; set; }
}
internal class Program
{
static void Main(string[] args)
{
var graphDefinition = File.ReadAllText("Graph.txt");
var regex = new Regex(#"\((?<Id>\d*),(?<Weight>\d*),(?<Left>\d*),(?<Right>\d*)\)");
var nodes = new List<Node>();
foreach (Match match in regex.Matches(graphDefinition))
{
nodes.Add(new Node
{
Id = int.Parse(match.Groups["Id"].Value),
Weight = int.Parse(match.Groups["Weight"].Value),
LeftId = match.Groups["Left"].Value,
RightId = match.Groups["Right"].Value
});
}
if (!nodes.Any())
return;
foreach (var node in nodes)
{
if (!string.IsNullOrEmpty(node.LeftId))
node.Left = nodes.FirstOrDefault(p => p.Id == int.Parse(node.LeftId));
if (!string.IsNullOrEmpty(node.RightId))
node.Right = nodes.FirstOrDefault(p => p.Id == int.Parse(node.RightId));
}
var root = nodes.First();
Depth(root, 0);
Console.WriteLine($"result calculation: {CalculatedMax}");
}
private static int CalculatedMax = int.MinValue;
private static void Depth(Node node, int currentSum)
{
if (node.Left == null && node.Right == null)
{
CalculatedMax = Math.Max(CalculatedMax, currentSum + node.Weight);
return;
}
Depth(node.Left, currentSum + node.Weight);
Depth(node.Right, currentSum + node.Weight);
}
}
Use table for input. Minus 1 is a node with no child. The table could be rows in a csv file.
After some thinking I realize you can build the tree from an array of numbers. You first create all the nodes in a list NODES with the values. Then you link the list into the binary tree.
class Program
{
static void Main(string[] args)
{
int[] data = { 3, 7, 6, 2, 4, 9, 1, 4, 8, 2 };
Node root = Node.BuildTree(data);
}
}
public class Node
{
int value { get; set; }
Node left { get; set; }
Node right { get; set; }
static List<Node> nodes { get; set; }
public static Node BuildTree(int[] input)
{
nodes = new List<Node>();
foreach(int i in input)
{
Node node = new Node();
node.left = null;
node.right = null;
node.value = i;
nodes.Add(node);
}
Node root = nodes[0];
int start = 0;
int row = 0;
while(start < nodes.Count)
{
int end = row + start;
for (int i = start; i < Math.Min(end + 1, nodes.Count); i++)
{
int col = i - start;
int leftChild = (end + 1 + col) < nodes.Count ? end + 1 + col : -1;
int rightChild = (end + 2 + col) < nodes.Count ? end + 2 + col : -1;
Console.WriteLine("row = {0}, col = {1}, left = {2}, right = {3}, start = {4}, end = {5}", row, col, leftChild, rightChild,start, end);
nodes[i].left = (leftChild == -1) ? null : nodes[leftChild];
nodes[i].right = (rightChild == -1) ? null : nodes[rightChild];
}
start = end + 1;
row++;
}
return root;
}
}

Why is tail.previous returning a null

Im implementing a stack using a linked list. I am having trouble with my pop method where tail.previous is null. I think this is because im trying to assign to the node after the tail which doesnt exist. if this is the case, how can i fix it.
class DynamicStack<T>
{
private class Node
{
public T element { get; private set; }
public Node Next { get; set; }
public Node Previous { get; set; }
public Node(T element, Node prevNode)
{
this.element = element;
Next = null;
Previous = null;
if (prevNode != null)
prevNode.Next = this;
}
}
private Node head, tail;
public int Count { get; private set; }
public DynamicStack()
{
this.head = null;
this.tail = null;
this.Count = 0;
}
public T Pop()
{
if (Count == 0)
return default(T);
Node temp = tail;
tail = tail.Previous;
Count--;
return temp.element;
}
}
I have tried doing the pop method as below but it doesnt follow LIFO so its not correct.
public T Pop()
{
if (Count == 0)
return default(T);
Node temp = head;
head = head.Next;
Count--;
return temp.element;
}

Lowest Common Ancestor in a Binary Tree, read the input and algorithm

I'm trainee and have a problem with that I can't solve this problem alone. So please help me. I found many topics but I could not find a solution.
I just start to learn C# and I'm not sure how to do this. I know that is a simple job but realy I need to understand and solve it. I try to do something but it is only some code. I did my binary tree with some values, have a node class and print method.
Please tell me how to write a code that can read a tree from the Console, because I don't want to have any hardcorde. And then how to find a lowest common ancestor - I see the BFS and DFS algorithms so maybe I can find something, but I'm not sure.
I've read much about this but I can not explain many things. Her
Here is the my code:
class Program
{
static void Main(string[] args)
{
var binatyTree = new BinaryTree<int>(1,
new BinaryTree<int>(2,
new BinaryTree<int>(4),
new BinaryTree<int>(5)),
new BinaryTree<int>(3,
new BinaryTree<int>(6,
new BinaryTree<int>(9),
new BinaryTree<int>(10)),
new BinaryTree<int>(7))
);
Console.WriteLine("Binary Tree:");
binatyTree.Print();
}
}
my binary tree and print method:
public class BinaryTree<T>
{
public T Value { get; set; }
public BinaryTree<T> LeftChildren { get; set; }
public BinaryTree<T> RightChildren { get; set; }
public BinaryTree(T value, BinaryTree<T> leftChildren = null, BinaryTree<T> rightChildren = null)
{
this.Value = value;
this.LeftChildren = leftChildren;
this.RightChildren = rightChildren;
}
public void Print (int indent = 0)
{
Console.Write(new string (' ', 2*indent));
Console.WriteLine(this.Value);
if (this.LeftChildren != null)
{
this.LeftChildren.Print(indent + 1);
}
if (this.RightChildren != null)
{
this.RightChildren.Print(indent + 1);
}
}
my class Node:
class Node
{
private int data;
private Node left;
private Node right;
public Node(int data = 0)
{
this.data = 0;
left = null;
right = null;
}
}
So please I realy need to understand every connections so please if you can explain for me and help.
So here is my Binary tree code.
using System;
namespace MyBinaryTree
{
// Creates a binary tree
// Finds the lowest common ancestor in a binary tree
class МainSolution
{
static void Main(string[] args)
{
// Initialises binary tree view
var btView = new ViewBinaryTree();
btView.BinaryTreeView();
// Initialises new binary tree
BinarySearchTree tree = new BinarySearchTree();
// Reads the desired number of nodes
Console.Write("Enter how many nodes you want: ");
int number = int.Parse(Console.ReadLine());
Console.WriteLine();
// Reads the nodes' values
for (int i = 1; i <= number; i++)
{
Console.Write($"Enter name of {i} node: ");
string nodeName = Console.ReadLine().ToUpper();
tree.Insert(nodeName);
}
// Lowest common ancestor - reads the two required values
// Checks the values
// Prints the lowest common ancestor
bool isValid = true;
while (isValid)
{
Console.WriteLine();
Console.Write("Please enter the first node value: ");
string nameOne = Console.ReadLine().ToUpper();
Console.Write("Please enter the second node value: ");
string nameTwo = Console.ReadLine().ToUpper();
if (tree.Find(nameOne) == true && tree.Find(nameTwo) == true)
{
Console.WriteLine();
var result = tree.SearchLCA(tree.root, nameOne, nameTwo);
Console.WriteLine($"Lowest common ancestor: {result} ");
Console.WriteLine();
isValid = false;
}
else
{
Console.WriteLine();
Console.WriteLine("Please enter a valid name!");
}
}
}
}
}
Create a class Node:
// Creates the node structure
class Node
{
public string Data { get; set; }
public Node RightChild { get; set; }
public Node LeftChild { get; set; }
public Node(string data, Node left = null, Node right = null)
{
this.Data = data;
this.LeftChild = left;
this.RightChild = right;
}
}
Here is my logic
// Creates a binary tree.
class BinarySearchTree
{
public Node root; // Creates a root node.
public BinarySearchTree()
{
this.root = null;
}
// Adds a node in the binary tree.
public void Insert(string inputValue)
{
Node newNode = new Node(inputValue); // Creates a new node.
if (root == null) // If the tree is empty, inserts the new node as root
{
root = newNode;
return;
}
//Determins where to place the new node in the binary tree.
Node current = root;
Node parent = null;
while (true)
{
parent = current;
if (inputValue.CompareTo(current.Data) < 0)
{
current = current.LeftChild;
if (current == null)
{
parent.LeftChild = newNode;
return;
}
}
else
{
current = current.RightChild;
if (current == null)
{
parent.RightChild = newNode;
return;
}
}
}
}
// Checks if the node exists in the binary tree
public bool Find(string inputValue)
{
Node current = root;
while (current != null)
{
if (current.Data.Equals(inputValue))
{
return true;
}
else if (current.Data.CompareTo(inputValue) > 0)
{
current = current.LeftChild;
}
else
{
current = current.RightChild;
}
}
return false;
}
// Creates a method to find the lowest common ancestor(LCA).
public object SearchLCA(Node searchTree, string compareValue1, string compareValue2)
{
if (searchTree == null)
{
return null;
}
if (searchTree.Data.CompareTo(compareValue1) > 0 && searchTree.Data.CompareTo(compareValue2) > 0)
{
return SearchLCA(searchTree.LeftChild, compareValue1, compareValue2);
}
if (searchTree.Data.CompareTo(compareValue1) < 0 && searchTree.Data.CompareTo(compareValue2) < 0)
{
return SearchLCA(searchTree.RightChild, compareValue1, compareValue2);
}
return searchTree.Data;
}
}
"Thank you!"

c# access custom linked list object's element

I have created custom linked list in c#.
LinkedList.cs:
class LinkedList
{
private Node Start;//Mazgas pr
private Node End;//Mazgas pb
private Node Current;// Mazas d saraso sasajai
public LinkedList()
{
this.Start = null;
this.End = null;
this.Current = null;
}
public Object Get(int index)
{
for( Node curr = Start; curr != null; curr = curr.Next)
{
if( curr.Index == index )
return curr.Data;
}
return null;
}
public void PrintData()
{
for (Node curr = Start; curr != null; curr = curr.Next)
{
Console.WriteLine("{0}: {1}", curr.Index, curr.Data);
}
}
public int Count()
{
int i = 0;
for( Node curr = Start; curr != null; curr = curr.Next, i++);
return i;
}
public void Add(Object data)
{
Node current = new Node(data, null);
if (Start != null)
{
End.Next = current;
End.Next.Index = End.Index + 1;
End = current;
}
else
{
Start = current;
End = current;
End.Index = 0;
}
}
}
Node.cs:
class Node
{
public Object Data { get; set; }
public Node Next { get; set; }
public int Index { get; set; }
public Node() { }
public Node(Object data, Node next )
{
Data = data;
Next = next;
}
public override string ToString ()
{
return string.Format ("Data: {0}", Data);
}
}
and Part.cs
class Part
{
public string Code { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public Part(string code, string name, double price)
{
Code = code;
Name = name;
Price = price;
}
public Part() { }
public override string ToString()
{
return string.Format("{0} {1}", Name, Code);
}
}
Problem is, when i create list LinkedList parts = new LinkedList()
and add objects to it parts.Add(new Part("code", "name", 10)); i can't access Part object variables. I need to do this:
for( int i=0; i<parts.Count(); i++)
{
Console.WriteLine("{0}", (Part)Parts.Get(i).Name);
}
but it gives me error:
Error CS1061: Type 'object' does not contain a definition for 'Name'
and no extension method 'Name' of type 'object' could be found. Are
you missing an assembly reference? (CS1061)
EDITED: I need this linked list to be flexible for any type of object.
(Part)Parts.Get(i).Name is equivalent to (Part)(Parts.Get(i).Name) and since return value of your Get(i) is of type object and object doesn't have Name property, you received the exception.
You can correct it this way:
((Part)Parts.Get(i)).Name
Note:
I suppose it's just for learning purpose.
If all items of the list are of the same type, you can make your Generic classes. Having a generic Node<T> and LinkedList<T> class you can change the input parameters and return values to T instead of object.
In a real application, you can use LinkedList<T> or other generic data structures available.

Best approach find position of an item in Lucene search results

I am using Lucene.NET and able to search get hit results as ScoreDoc[].
I need to know specific item position in ScoreDoc[]. All items in ScoreDoc[] are unique.
Sample code:
luceneSearcher.Search(query, collector);
ScoreDoc[] scores = collector.TopDocs().scoreDocs
For example, I need to get find item position in ScoreDoc[], which has custom ID property where value could be '99999'.
I can iterate through item in scores[] and check for ID property which matches '99999' then return the position, but this can have performance hit because scores[] can have thousands of items.
Is there any better technique?
Thanks
I came up with creating new ExtendedCollector which stores CollectedDocuments.
public class ExtendedCollector : Collector
{
private Scorer _scorer;
private Int32 _docBase;
private List<CollectedDocument> _documents;
public ExtendedCollector()
{
_documents = new List<CollectedDocument>();
}
public override void SetScorer(Scorer scorer)
{
_scorer = scorer;
}
public override void Collect(int doc)
{
var docId = _docBase + doc;
var score = _scorer.Score();
var currentDoc = _documents.FirstOrDefault(d => d.DocId == docId);
if (currentDoc == null)
_documents.Add(new CollectedDocument()
{DocId = docId, Score = score, OriginalIndex = _documents.Count, Index = _documents.Count});
else
currentDoc.Score = score;
}
public override void SetNextReader(IndexReader reader, int docBase)
{
_docBase = docBase;
}
public override bool AcceptsDocsOutOfOrder()
{
return false;
}
public List<CollectedDocument> Documents
{
get { return _documents; }
}
public List<CollectedDocument> DocumentsByScore
{
get
{
var result = _documents.OrderByDescending(d => d.Score).ToList();
var itemId = 0;
foreach (var collectedDocument in result)
{
itemId++;
collectedDocument.Index = itemId;
}
return result;
}
}
}
CollectedDocument looks like this
public class CollectedDocument
{
public Int32 DocId { get; set; }
public float Score { get; set; }
public int OriginalIndex { get; set; }
public int Index { get; set; }
}
Whenever you want to get results you would do
var myCollector = new ExtendedCollector();
searcher.Search(searchQuery, myCollector);
foreach (var doc in myCollector.Documents)
{
var docIndex = doc.Index; //this is the current index in a list
var originalIndex = doc.OriginalIndex; //this is item Id set when doc was collected
}
You can also get the documents ordered by score using
myCollector.DocumentsByScore
This might not be the easiest solution, but it works. If anyone has a better solution, please post it as I'd like to know that as well.

Categories

Resources