I notice i do this pattern a lot. Is there a better way to write this?
bool hit=false;
foreach (var tag in tags)
if (tag == sz)
{
hit = true;
break;
}
if (hit) continue;
//tags.add(sz); or whatever i wanted to do
I know if sz in tags exist in other languages. I hope theres something in linq that can help?
For the example:
if (tags.Contains(sz)) ...
For the more general problem:
if (tags.Any(tag => InvolvedLogic(tag))) ...
Assuming tags is a List<T>:
if (tags.Contains(sz))
{
// ...
}
If you just want to know if a given item is in tags, do:
if(tags.Any(t => t == sz))
{
// Do stuff here
}
If you want to grab a reference to the found item, do:
var foundTag = tags.FirstOrDefault(t => t == sz);
// foundTag is either the first tag matching the predicate,
// or the default value of your tag type
if (tags.Any(t=>t == sz) == true)
{
//...
}
Related
I originally asked this question (Can we automatically add a child element to an XElement in a sortable manner?) and it was closed as a duplicate (how to add XElement in specific location in XML Document).
This is teh code that I have at the moment:
bool bInserted = false;
foreach (var weekDB in xdoc.Root.Elements())
{
DateTime datWeekDB = DateTime.ParseExact(weekDB.Name.LocalName, "WyyyyMMdd", CultureInfo.InvariantCulture);
if (datWeekDB != null && datWeekDB.Date > historyWeek.Week.Date)
{
// Insert here
weekDB.AddBeforeSelf(xmlHistoryWeek);
bInserted = true;
break;
}
}
if (!bInserted)
xdoc.Root.Add(xmlHistoryWeek);
It works fine. But I wondered if I can use LINQ to acheive the same thing? The linked answer suggests:
Search element you want to add and use Add method as shown below
xDoc.Element("content")
.Elements("item")
.Where(item => item.Attribute("id").Value == "2").FirstOrDefault()
.AddAfterSelf(new XElement("item", "C", new XAttribute("id", "3")));
But I don't understand how to end up with logic like that based on my codes logic.
I think the best way to think about it is: you are going to use LINQ to find a specific element. Then you will insert into the document based on what you found.
So something like this:
var targetElement = xdoc.Root.Elements()
.Where(weekDB => {
DateTime datWeekDB = DateTime.ParseExact(weekDB.Name.LocalName, "WyyyyMMdd", CultureInfo.InvariantCulture);
return datWeekDB != null && datWeekDB.Date > historyWeek.Week.Date;
})
.FirstOrDefault();
if (targetElement == null)
{
xdoc.Root.Add(xmlHistoryWeek);
}
else
{
targetElement.AddBeforeSelf(xmlHistoryWeek);
}
foreach (Objecta a in aList())
{
foreach (Objectb b in bList)
{
if (a.variable != b.variable1 && a.variable() != b.variable2)
{
a.setVariable("Error");
}
}
}
The problem I am getting is that it goes through the foreach loop the first time and it sets variable to error without checking if other values (when it goes through the loop again) finds a match.
What I would like is to wait until it goes through all the lists and at the last foreach loop iteration if nothing in aList matches the variable target && variable source in bList then finally set it to Error flag.
Any suggestions to get around this will be appreciated.
Try doing it the other way around. Search for a match instead of searching for non-matches.
foreach (Objecta a in aList())
{
bool foundMatch = false;
foreach (Objectb b in bList)
{
if (a.variable == b.variable1 || a.variable() == b.variable2)
{
foundMatch = true;
break;
}
}
if (!foundMatch)
{
a.setVariable("Error");
}
}
I think this is what you are looking for. So if StoreList is the outer loop and LinkList is the inner loop. You want to search all the links to see if there's an ID that matches the store ID. If you find a match, stop searching the links. After the search through the links, set an error on the store if there was no match, then go to the next store.
foreach (Objecta a in aList())
{
var foundMatch = false;
foreach (Objectb b in bList)
{
if (a.variable == b.variable1 || a.variable() == b.variable2)
{
fondMatch = true;
break;
}
}
if (!foundMatch) a.setVariable("Error");
}
I think you want something like this:
First select all the item values from aList and bList and put them in a seperate array:
var aVals = aList.Select(x=>x.value1).ToArray();
var bListVals1 = bItems.Select(x=>x.value1).ToArray();
var bListVals2 = bItems.Select(x=>x.value2).ToArray();
var bVals = bListVals1.Concat(bListVals2);
Then, get the values both lists have in common:
var correctVals = bVals.Intersect(aVals);
These are the correct values and so all the other values are wrong:
var wrongVals = aVals.Except(correctVals);
Now you have the values that are wrong and can act accordingly:
wrongAItems = aList.Where(a => wrongVals.Contains(a.value));
foreach(wrongA in wrongAItems){
wrongA.setVariable("Error");
}
foreach (Store s in processFlowStores.getStoresList())
{
if (!processFlowLinks.Any(l => s.getNodeId() == l.getLinkSource() ||
s.getNodeId() == l.getLinkTarget()))
{
s.setID("Error: FailedOperation Error - 123.123.121");
}
}
EDIT: more compact solution using Linq. Basically, if none of the links has it as either source or target, mark it as error.
I ran into some problem in Unity, How am I supposed to remove an item from a List by its ID or name? I think this should work, but evidentally it doesn't.
....
List<MyDataType> myList = new List<MyDataType>();
....
public static void removeItemFromList(int id)
{
foreach (MyDataType item in myList)
{
if (item.TypeId == id)
Debug.Log("List contains ID: " + item.TypeId);
}
// PRINTS AN OBJECT WITH THE ID - works as expected
var match = myList.Find(p => p.TypeId == id);
// SEEMS LIKE IT CAN'T FIND THE OBJECT WITH THE ID
if (match == null)
{
Debug.Log("DOES NOT EXIST");
return;
}
// always returns DOES NOT EXIST, WHY?
myList.Remove(match);
}
I don't have unity in front of me,
but you could try myList.Select(item => item.TypeId == id).SingleOrDefault();
or as Fabjan states:
myList.SingleOrDefault(item => item.TypeId == id);
Jasper is correct, but make sure that you add the LINQ library to your project or you won't have access to FirstOrDefault on a list. That may be why you couldn't find the definition for it.
using System.Linq;
How can I use lambda inside an if statement to compare a treenode's value to an object value inside a list ? Currently I am trying something like this but it won't work. Is there any better way to simplify my search?
if (tvItems.Nodes.Count > 0)
{
// Get checked items
listChecked= MenuItemDTOManager.GetMenuItems();
//
foreach (TreeNode parentNode in tvItems.Nodes)
{
if (listChecked.Find(s => s.menuId.ToString() == parentNode.Value.ToString()))
{
parentNode.Checked = true;
}
}
// Traverse children
}
Should be using Any instead of Find:
if (listChecked.Any(s => s.menuId.ToString() == parentNode.Value.ToString()))
{
parentNode.Checked = true;
}
if requires a bool value only.
listChecked.Find(s => s.menuId.ToString() == parentNode.Value.ToString())
Find won't return bool.
Try using Exists instead of Find.
Probably you are looking for the following.
foreach (TreeNode parentNode in tvItems.Nodes.OfType<TreeNode>().Any(n=> listChecked.Any(s => s.menuId.ToString() == n.Value.ToString()))
{
parentNode.Checked = true;
}
I'm just trying to teach myself how to use Linq. This is what I have
if (FileReceivers.Exists(t => t.FileName == filename))
{
//I also want to do a c.Parent = proper FileReceiver
FileReceivers.Where(t=>t.FileName == filename).First().Clients.Add(c);
}
else
{
FileReceiver fr = new FileReceiver(filename);
fr.Clients.Add(c);
FileReceivers.Add(fr);
}
Any ideas how I would do this the right way? I don't really want to be using Linq to twice to grab the same thing, that would defeat the purpose.
I would just like to know the proper way to format this.
var fr = FileReceivers.FirstOrDefault(t=>t.FileName == filename);
if (fr == null) {
fr = new FileReceiver(filename);
FileReceivers.Add(fr);
}
fr.Clients.Add(c);
you could always pass the results of t => t.FileName == filename to an anonymous type and use that for later processing.