convert recursive code to LINQ - c#

I want to convert this recursive call to LINQ but I am not sure how to do the last two conditions. Please advise on how to add these last two conditions.
private void findGoogleOrganic(HtmlNode node)
{
if (node.Attributes["class"] != null)
{
if (node.Attributes["class"].Value.ToString().Contains("r ld"))
{
String tmp;
tmp = node.ParentNode.InnerHtml.ToString();
bool condition1 = false;
bool condition2 = false;
if (tmp != null)
{
**condition1 = tmp.Contains("qcp47e");
condition2 = tmp.Contains("r ld");**
}
**if (condition1 == false && condition2 == true)**
{
GoogleOrganicResults.Add(new Result(URLGoogleOrganic, Listing, node, SearchEngine.Google, SearchType.Organic, ResultType.Website));
}
}
}
if (node.HasChildNodes)
{
foreach (HtmlNode children in node.ChildNodes)
{
findGoogleOrganic(children);
}
}
}
Here is My first attempt without the last two conditions:
private void findGoogleOrganicLINQ(HtmlNode node)
{
var results = node.Descendants()
.Where(x => x.Attributes["class"] != null &&
x.Attributes["class"].Value.Contains("r ld"))
.Select(x => new Result(URLGoogleLocal, Listing, x, SearchEngine.Google, SearchType.Local, ResultType.GooglePlaces));
foreach (Result x in results)
{
GoogleOrganicResults.Add(x);
}
}

if(node.HasChildNodes)
{
node.ChildNodes.ForEach(findGoogleOrganic);
}

Related

What 's the best solution to find an element in a deepest binary tree

Recently I had an interview question about finding an element in a binary tree. I coded both recursive and iterative solutions with C# but the problem was that in test cases when we have a tree with 1000000 nodes and all of them are on the left side. The interviewer said to me that my solutions (recursive and iterative) didn't save memory RAM enough for this case and I don't understand how to improve my solution.
// recusive Mode
public Node Find(int v)
{
if(v == value)
{
return this;
}else if(v <value){
if (left == null) return null;
return left.Find(v);
}else{
if (right == null) return null;
return right.Find(v);
}
}
// iterative
public Node Find(int v)
{
Node current = this;
while(value != v && current != null)
{
if (v < current.value)
{
if (current.left == null){ current = null};
else{current = current.left};
}
else
{
if (current.right == null) { current = null};
else{current = current.right };
}
}
return current;
}
Your iterative solution has some bugs in it.
// iterative
public Node Find(int v)
{
Node current = this;
// Here you need to compare current.value instead of just value
// Also, to use short-circuiting you need to put null-check first
// otherwise you might access current.value while current is null
while(current != null && current.value != v)
{
if (v < current.value)
{
//if (current.left == null){ current = null};
//else{current = current.left};
current = current.left; // the same as two commented out lines
}
else
{
//if (current.right == null) { current = null};
//else{current = current.right };
current = current.right; // the same as two commented out lines
}
}
return current;
}

Serialize arithmetic expression-tree

I'm doing a simple task for investigation purposes. The problem is as follows:
Create an arithmetic expression with variables.
Build an AST for the expression.
Send it to the server (using Sockets)
Calculate an result of the server side and return the results.
Now I can to build a tree. This method doing it:
private readonly Stack<Expression> expressionStack = new Stack<Expression>();
private readonly Stack<Symbol> operatorStack = new Stack<Symbol>();
private readonly List<string> parameters = new List<string>();
public Expression<Func<decimal[], decimal>> Parse(string expression)
{
if (string.IsNullOrWhiteSpace(expression))
{
return s => 0;
}
var arrayParameter = Expression.Parameter(typeof(decimal[]), "args");
parameters.Clear();
operatorStack.Clear();
expressionStack.Clear();
using (var reader = new StringReader(expression))
{
int peek;
while ((peek = reader.Peek()) > -1)
{
var next = (char)peek;
if (char.IsDigit(next))
{
expressionStack.Push(ReadOperand(reader));
continue;
}
if (char.IsLetter(next))
{
expressionStack.Push(ReadParameter(reader, arrayParameter));
continue;
}
if (Operation.IsDefined(next))
{
if (next == '-' && expressionStack.Count == 0)
{
reader.Read();
operatorStack.Push(Operation.UnaryMinus);
continue;
}
var currentOperation = ReadOperation(reader);
EvaluateWhile(() => operatorStack.Count > 0 && operatorStack.Peek() != Parentheses.Left &&
currentOperation.Precedence <= ((Operation)operatorStack.Peek()).Precedence);
operatorStack.Push(currentOperation);
continue;
}
if (next == '(')
{
reader.Read();
operatorStack.Push(Parentheses.Left);
if (reader.Peek() == '-')
{
reader.Read();
operatorStack.Push(Operation.UnaryMinus);
}
continue;
}
if (next == ')')
{
reader.Read();
EvaluateWhile(() => operatorStack.Count > 0 && operatorStack.Peek() != Parentheses.Left);
operatorStack.Pop();
continue;
}
if (next == ' ')
{
reader.Read();
}
else
{
throw new ArgumentException(string.Format("Encountered invalid character {0}", next),
"expression");
}
}
}
EvaluateWhile(() => operatorStack.Count > 0);
return Expression.Lambda<Func<decimal[], decimal>>(expressionStack.Pop(), arrayParameter);
}
This method works, and returns the expected result.
Before being sent to the server I want to serialize a tree to binary type. My question is as follows. Which is the simplest way I can apply for this?
I found a lot of solutions for LINQ serialization, but they are too big. I don't need the full functionality of these solutions. In addition, usually, they provide the JSON or XML-serialization, but I need a binary serialization.
Can somebody suggest a simple and easy solution for this problem?

C# HTML Tag in a Tag

I have a bit of a pickle. There are a list of images I want to grab on a website. I know how to do that much, but I have to filter out the location of the images.
Such as I'd want to grab the images in a div tag with an id "theseImages", but there are another set of images within another div tag with an id called "notTheseImages". Looping through every tag into ah HtmlElementCollection with the tag "img" would ignore the divs, because it'd also grab the images from "notTheseImages."
Is there a way I could loop through the images while doing a check to see where those images are located in the div tags?
This could help you to do the selection of your current HTML and maybe for future occassions :)
protected HtmlElement[] GetElementsByParent(HtmlDocument document, HtmlElement baseElement = null, params string[] singleSelectors)
{
if (singleSelectors == null || singleSelectors.Length == 0)
{
throw new Exception("Please give at least 1 selector!");
}
IList<HtmlElement> result = new List<HtmlElement>();
bool last = singleSelectors.Length == 1;
string singleSelector = singleSelectors[0];
if (string.IsNullOrWhiteSpace(singleSelector) || string.IsNullOrWhiteSpace(singleSelector.Trim()))
{
return null;
}
singleSelector = singleSelector.Trim();
if (singleSelector.StartsWith("#"))
{
var item = document.GetElementById(singleSelector.Substring(1));
if (item == null)
{
return null;
}
if (last)
{
result.Add(item);
}
else
{
var results = GetElementsByParent(document, item, singleSelectors.Skip(1).ToArray());
if (results != null && results.Length > 0)
{
foreach (var res in results)
{
result.Add(res);
}
}
}
}
else if (singleSelector.StartsWith("."))
{
if (baseElement == null)
{
baseElement = document.Body;
}
foreach (HtmlElement child in baseElement.Children)
{
string cls;
if (!string.IsNullOrWhiteSpace((cls = child.GetAttribute("class"))))
{
if (cls.Split(' ').Contains(singleSelector.Substring(1)))
{
if (last)
{
result.Add(child);
}
else
{
var results = GetElementsByParent(document, child, singleSelectors.Skip(1).ToArray());
if (results != null && results.Length > 0)
{
foreach (var res in results)
{
result.Add(res);
}
}
}
}
}
}
}
else
{
HtmlElementCollection elements = null;
if (baseElement != null)
{
elements = baseElement.GetElementsByTagName(singleSelector);
}
else
{
elements = document.GetElementsByTagName(singleSelector);
}
foreach (HtmlElement item in elements)
{
if (last)
{
result.Add(item);
}
else
{
var results = GetElementsByParent(document, item, singleSelectors.Skip(1).ToArray());
if (results != null && results.Length > 0)
{
foreach (var res in results)
{
result.Add(res);
}
}
}
}
}
return result.ToArray();
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// here we can query
var result = GetElementsByParent(webBrowser1.Document, null, "#theseImages", "img");
}
result would then contain the images that are under #theseImages
Mind you the GetElementsByParent is fairly untested, I just tested it for your use case and it seemed to be ok.
Don't forget to only start the query once you are sure the document is completed ;)

Getting rid of unnecessary loops

In my game I'm going to have a lot of interactions in which I'll need to see if a player has an item, and if he does and something else is true, then do an action. Described in the following code.
private void SetTinderInPit()
{
MouseState currentMouseState = Mouse.GetState();
if (player.NextToFirePit == true)
{
foreach (Item item in player.PlayerInventory.Items)
{
if (item.ItemName == "tinder")
{
foreach (Item pit in allItemsOnGround)
{
if (pit.ItemName == "firepit" &&
pit.ItemRectangle.Contains(MouseWorldPosition) &&
currentMouseState.LeftButton == ButtonState.Pressed &&
oldMouseState.LeftButton == ButtonState.Released)
{
item.ItemName = "empty";
pit.ItemName = "firepitwithtinder";
pit.Texture = Content.Load<Texture2D>("firepitwithtinder");
}
}
}
}
oldMouseState = currentMouseState;
}
}
As you can see, this is ugly to look at and I think that there would be a better way to do this, but I'm not sure how. Since there will be a lot of these types of methods, I'm wondering what would be the best way to accomplish this?
Seems like you could get rid of (actually hide) the loops altogether by using some LINQ:
private void SetTinderInPit()
{
MouseState currentMouseState = Mouse.GetState();
if (player.NextToFirePit)
{
Item tinder = player.PlayerInventory.Items.FirstOrDefault(i => i.ItemName == "tinder");
if (tinder != null)
{
Item firepit = allItemsOnGround.FirstOrDefault(i => i.ItemName == "firepit" && i.ItemRectangle.Contains(MouseWorldPosition));
if (firepit != null &&
currentMouseState.LeftButton == ButtonState.Pressed &&
oldMouseState.LeftButton == ButtonState.Released)
{
tinder.ItemName = "empty";
firepit.ItemName = "firepitwithtinder";
firepit.Texture = Content.Load<Texture2D>("firepitwithtinder");
}
}
oldMouseState = currentMouseState;
}
}
This has the added advantage of short-circuiting the loop when the item is found. It also makes it easy to check against things other than the name (like an "IsFlammable" or "CanContainFire" property) so you could use multiple items instead of just "tinder" and "firepit".
If you actually intended to remove all firepits and tinder, use:
private void SetTinderInPit()
{
MouseState currentMouseState = Mouse.GetState();
if (player.NextToFirePit)
{
foreach (Item tinder in player.PlayerInventory.Items.Where(i => i.ItemName == "tinder")
{
foreach (Item firepit in allItemsOnGround.Where(i => i.ItemName == "firepit"))
{
if (firepit.ItemRectangle.Contains(MouseWorldPosition) &&
currentMouseState.LeftButton == ButtonState.Pressed &&
oldMouseState.LeftButton == ButtonState.Released)
{
tinder.ItemName = "empty";
firepit.ItemName = "firepitwithtinder";
firepit.Texture = Content.Load<Texture2D>("firepitwithtinder");
}
}
}
oldMouseState = currentMouseState;
}
}
Quick caveat; this code will remove all firepits with the first tinder, leaving the other tinders unscathed. I could unravel the loops to remove everything, but this function matches the provided one; and besides, I'm assuming thats not the intended behavior.
Note you do not need ToList anywhere because you are not modifying the collection during enumeration. You can always modify the items in the collection, proved with the following test:
class IntWrapper
{
public int value;
public IntWrapper(int value)
{
this.value = value;
}
}
class Program
{
static void Main(string[] args)
{
List<IntWrapper> test = new List<IntWrapper>() { new IntWrapper(1), new IntWrapper(2), new IntWrapper(3), new IntWrapper(4), new IntWrapper(5) };
foreach (IntWrapper i in test.Where(i => i.value == 1))
{
i.value = 0;
}
foreach (IntWrapper i in test)
{
Console.WriteLine(i.value);
}
Console.ReadLine();
}
}
The only real change I would make to your existing code would be to move the check for mouse state early on, to avoid checking this multiple times in your loops. In addition I would use Linq to shorten the conditions (by removing the 'if' statements):
MouseState currentMouseState = Mouse.GetState();
// I would get all the conditional checks out of the way up front first
if (player.NextToFirePit &&
currentMouseState.LeftButton == ButtonState.Pressed &&
oldMouseState.LeftButton == ButtonState.Released)
{
foreach (var tinderItem in player.PlayerInventory.Items
.Where(item => item.ItemName == "tinder"))
{
foreach (var firePit in allItemsOnGround
.Where(item => item.ItemName == "firepit" &&
item.ItemRectangle.Contains(MouseWorldPosition)))
{
tinderItem.ItemName = "empty";
firePit.ItemName = "firepitwithtinder";
firePit.Texture = Content.Load<Texture2D>("firepitwithtinder");
}
}
}
oldMouseState = currentMouseState;
An alternate idea, since you were looking for a way to get rid of the 'ugly' code, would be to move some of this functionality to the player object.
I would probably use LINQ more.
Note that this is written in Notepad, not visual studio so is more of a pseudo-code.
private void SetTinderInPit()
{
var currentMouseState = Mouse.GetState();
if (!player.NextToFirePit) return;
player.PlayerInventory.Items.Where(item => item.ItemName == "tinder").ToList().ForEach(item =>
{
allItemsOnGround.Where(x => x.ItemName == "firepit" &&
x.ItemRectangle.Contains(MouseWorldPosition) &&
currentMouseState.LeftButton == ButtonState.Pressed &&
oldMouseState.LeftButton == ButtonState.Released)
.ToList().ForEach(pit =>
{
item.ItemName = "empty";
pit.ItemName = "firepitwithtinder";
pit.Texture = Content.Load<Texture2D>("firepitwithtinder");
});
});
oldMouseState = currentMouseState;
}

Is there a method for searching for TreeNode.Text field in TreeView.Nodes collection?

Like this:
TreeNode[] treeNodes = treeView.Nodes.Find(searchString, true);
but I want it to search in the text field instead of the name field.
I am not aware of any inbuilt method but you may use LINQ
TreeNode[] treeNodes = treeView.Nodes
.Cast<TreeNode>()
.Where(r => r.Text == "yourText")
.ToArray();
To search all tree nodes (not only the direct child nodes) you can use the extension method below
var nodes = treeView1.FlattenTree()
.Where(n => n.Text == "sometext")
.ToList();
--
public static class SOExtension
{
public static IEnumerable<TreeNode> FlattenTree(this TreeView tv)
{
return FlattenTree(tv.Nodes);
}
public static IEnumerable<TreeNode> FlattenTree(this TreeNodeCollection coll)
{
return coll.Cast<TreeNode>()
.Concat(coll.Cast<TreeNode>()
.SelectMany(x => FlattenTree(x.Nodes)));
}
}
If I understand you correctly (you last question was very confusing), you can write a find method yourself as follows
public static TreeNode[] Find(this TreeNode motherNode, string findNodeText)
{
List<TreeNode> nodeList = new List<TreeNode>();
foreach (TreeNode childNode in motherNode.Nodes)
if (childNode.Text.Equals(findNodeText, StringComparison.CurrentCulture))
nodeList.Add(childNode);
return nodeList.ToArray<TreeNode>();
}
This method can be used like
TreeView myTreeView = new TreeView();
foreach (TreeNode node in myTreeView.Nodes)
{
TreeNode[] childNodes = node.Find("Text");
// Do something...
}
I hope this helps.
The following code only shows the nodes which matches the search criteria.
Copy the following code in the search event
private void tbxSearch_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
trvMenu.BeginUpdate();
if (tbxSearch.Text.Length > 0)
{
for (int i = trvMenu.Nodes.Count; i > 0 ; i--)
{
NodeFiltering(trvMenu.Nodes[i - 1], tbxSearch.Text);
}
}
trvMenu.EndUpdate();
}
Then create the serch & filter function
private bool NodeFiltering(TreeNode Nodo,string Texto)
{
bool resultado = false;
if (Nodo.Nodes.Count == 0)
{
if (Nodo.Text.ToUpper().Contains(Texto.ToUpper()))
{
resultado = true;
}
else
{
Nodo.Remove();
}
}
else
{
for (int i = Nodo.Nodes.Count; i > 0; i--)
{
if (NodeFiltering(Nodo.Nodes[i - 1], Texto))
resultado = true;
}
if (!resultado)
Nodo.Remove();
}
return resultado;
}
This code is pretty nice for creating Treeview menus with many levels.

Categories

Resources