Set a field in all the children of an item - c#

I have an Item in sitecore lets say "AddressItem" that has some children. I want to edit a Field "IsMain" in all the child items.
I am using Foreach loop. Is there some better way to achieve this.
foreach (Sitecore.Data.Items.Item child in AddressItem.Children)
{
using (new SecurityDisabler())
{
child.Editing.BeginEdit();
child.Fields["IsMain"].Value = "0";
child.Editing.EndEdit();
}
}

Its probably faster to set the IsMain fields standard value to 0 then reset all items to that standard value. There is no function for that out of the box but the below code will do it.
This function is a little more robust then your requirement but its the code I have as is.
First you need a user with the correct permissions to replace: ElevatedUserAccount
Next get the list of items you would like to reset the values for then create a list of fields you wish to reset. In your case AddressItem.Children and IsMain.
Finally pass them into the below methods.
public void ResetFields(List<Item> items, List<string> fields)
{
if (items.Any() && fields.Any())
{
foreach (Item item in items)
{
ResetFieldsOnItem(item, fields);
}
}
}
public void ResetFieldsOnItem(Item item, List<string> fields)
{
if (item != null && fields.Any())
{
using (new Sitecore.Security.Accounts.UserSwitcher(ElevatedUserAccount, true))
{
item.Editing.BeginEdit();
foreach (string field in fields)
{
item.Fields[field].Reset();
}
item.Editing.EndEdit();
}
}
}

Related

How to remove contents from list

I'm very new to coding. Is there any other way through which I can write this code to remove contents from list in c#?
public void RemoveItem(string itemDescription)
{
MenuItem found = new MenuItem(false, 0, "", ""); // must be a better way - to fix
foreach (MenuItem item in MenuItems)
{
if (item.Description == itemDescription)
{
found = item;
}
}
MenuItems.Remove(found);
}
There are several ways how to improve this code. Some of them were already mentioned.
As commented by #tim-schmelter
// removes the last matching occurrence from the menu and avoids the "dummy" object
public void RemoveItem(string itemDescription)
{
MenuItem found = null; // this is better
foreach (MenuItem item in MenuItems)
{
if (item.Description == itemDescription)
{
found = item;
}
}
if (found != null)
MenuItems.Remove(found);
}
As originally answered by #SomeBody
// removes the first matching occurrence from the menu
public void RemoveItem(string itemDescription)
{
foreach (MenuItem item in MenuItems)
{
if (item.Description == itemDescription)
{
MenuItems.Remove(found);
break; // or return;
}
}
}
// same but replacing the loop with a LINQ approach
public void RemoveItem(string itemDescription)
{
MenuItem found = MenuItems.FirstOrDefault(item => item.Description == itemDescription);
if (found != null)
MenuItems.Remove(found);
}
// removing all occurences (assumes that MenuItems is from type `List<MenuItem>`
public void RemoveItem(string itemDescription)
{
MenuItems.RemoveAll(item => item.Description == itemDescription);
}
// assuming List<MenuItem>, removing the first occurrence only
public void RemoveItem(string itemDescription)
{
int index = MenuItems.Find(item => item.Description == itemDescription);
if (index >= 0)
MenuItems.RemoveAt(index);
}
I'm assuming that MenuItems is a List<MenuItem>.
In which case, as Johnathan says in the comments MenuItems.RemoveAll(item => item.Description == itemDescription); will remove all elements in the list that match your criteria and is probably the most efficient option:
public void RemoveItem(string itemDescription)
{
MenuItems.RemoveAll(item => item.Description == itemDescription);
}
Ideally, though, I'd use an ID field to make sure you're definitely removing the right element.
From a performance perspective there is another solution which especially makes sense if a list grows very huge or is traversed very often (which is hopefully not the case for a menu list).
Most of the so far given answers require two lookups (one for finding the item, one for removing the item), or have some overhead by calling a predicate function.
The following is probably the fastest method and works with every collection implementing IList<T>:
// remove last matching item
public void RemoveItem(string itemDescription)
{
for (int i = MenuItems.Count - 1; i >= 0; i--) // reverse for-loop, to avoid Count property call on each iteration
{
if (MenuItems[i].Description == itemDescription)
{
MenuItems.RemoveAt(i);
return;
}
}
#geraldmayr answer is great.
Only thing I would change is the approach of the original answer in LINQ to make it a clean one liner.
public static void RemoveItem(string itemDescription)
{
menuItems.Remove(menuItems.First(menuItem => menuItem.ItemDescription == itemDescription));
}

Comparing two large lists and assigning property values from another

I have a very simple method of comparing two lists and then assigning the value from first list to second like following:
private void FindUPC(List<ResultItem> filteredProducts, List<zsp_select_UserItems_Result> items)
{
foreach (var item in items)
{
foreach (var trItem in filteredProducts)
{
if (item.ItemID == trItem.ID)
{
trItem.UPC = item.UPC;
trItem.EAN = item.EAN;
trItem.MPN = item.MPN;
}
}
}
}
However, when doing it like this on large collections such as let's say comparing collection where each list contains 50000 items inside, the execution time that it takes here is a whooping 30000 miliseconds (30 seconds)... This impacts the performance terribly, so I'm wondering what is the fastest way to compare two lists and then assign the values like I've shown in my previous example that I wrote?
Can someone help me out?
P.S. Guys can I use IEqualityComparer for this?
#Stephen did you mean something like this:
private void FindUPC(List<ResultItem> filteredProducts, List<zsp_select_UserItems_Result> items)
{
foreach (var item in items)
{
foreach (var trItem in filteredProducts)
{
if (item.ItemID == trItem.ID)
{
trItem.UPC = item.UPC;
trItem.EAN = item.EAN;
trItem.MPN = item.MPN;
}
break;
}
}
}
Load all your items into a data structure with constant lookup. Then perform your loop.
private void FindUPC(List<ResultItem> filteredProducts, List<zsp_select_UserItems_Result> items)
{
var itemsDict = items.ToDictionary(i => i.ItemID);
foreach (var trItem in filteredProducts)
{
if (itemsDict.TryGetValue(trItem.ID, out var item)) {
trItem.UPC = item.UPC;
trItem.EAN = item.EAN;
trItem.MPN = item.MPN;
{
}
}

Updating data of a nested list with linq

I have a user object that contains a nested list and i need to change the value of a element in the 3rd list and return the user object.
I want to do this with linq, below is the nested loop.
foreach (User itm in user)
{
if (itm.destinations!=null)
{
foreach (Models.Api.destinations.Destination dm in itm.destinations)
{
if (dm.destinationData != null)
{
foreach (Models.Api.destinations.DestinationData destData in dm.destinationData)
{
if (destData.type == "phone" & destData.data!="")
{
//i want to update the destData.data here .. something like
destData.data ='updated data';
}
}
}
}
}
}
I want the updated data to be available in the user object
can someone help me achieve this with the LINQ
Thanks in advance
Tarak
Try this:
foreach (var x in
(from itm in user
where itm.destinations!=null
from dm in itm.destinations
where dm.destinationData != null
from destData in dm.destinationData
where destData.type == "phone" & destData.data != ""
select new { itm, dm, destData }))
{
/* put your update code here. */
}
You didn't give us what the update code should look like or even the object models for us to work from.

Updating A List With Linq

Assuming I have some objects like this:
Class NetworkSwitch
{
private String _name;
String name { get {return _name;} set {_name=value;}}
Dictionary<int, VLAN> VLANDict = new Dictionary<int, NetworkSwitch>();
public List<CiscoSwitch> GetAllNeigbors()
{
List<CiscoSwitch> templist = new List<CiscoSwitch>();
foreach (KeyValuePair<int, CiscoVSAN> vlanpair in this.VLANDict)
{
templist.AddRange((vlanpair.Value.NeighborsList.Except(templist, new SwitchByNameComparer())).ToList());
}
return templist;
}
Class VLAN
{
private Int _VLANNum;
Int VLANNum {get {return _VLANNum ;} set {_VLANNum =value;}}
//a neighbor is another switch this switch is connected to in this VLAN
// the neighbor may not have all same VLANs
List<NetworkSwitch> Neighbors = new List<NetworkSwitch>();
}
the above is designed that way because two switches that are physically connected may not have all the same VLANs assigned. what I am attempting to do is step through the Neighbors list in each VLAN on a given switch and update the reference to another switch if the name matches one in an input list. Here is what I tried and it won't compile. I am wondering if LINQ can do it in place somehow, or if there is a better approach.
// intersect is the input list of NetworkSwitch objects
//MyNetworkSwitch is a previously created switch
foreach (NetworkSwitch ns in intersect)
{
foreach (KeyValuePair<int, VLAN> vlanpair in MyNetworSwitch.VLANDict)
{
foreach (CiscoSwitch neighbor in vlanpair.Value.Neighbors)
{ // this is the line that fails - I can't update neighbor as it is part of the foreach
if (ns.name == neighbor.name) { neighbor = ns; }
}
}
}
Another question - I added the method that gets all the neighbors for a NetworkSwitch object. Assuming I were to get that list, then update it with references to a different instance of the switch with the same name, would that update the reference in the VLAN for the NetworkSwitch object?
Something like this should work:
foreach (NetworkSwitch ns in intersect)
{
foreach (KeyValuePair<int, VLAN> vlanpair in ns.VLANDict)
{
if(vlanpair.Value.Neighbors.RemoveAll(n => n.name == ns.name) > 0)
vlanpair.Value.Neighbors.Add(ns);
}
}
Due to how IEnumerable works, changing the contents of an Enumerable while iterating over it is not a supported action.
You will either have to return a new list with the changed values and then update the original reference, or use a plain ol' for (...; ...; ...) loop.

Compare List<string> and enable the required control

I am having two list<string> as follows
listA is having the following values 10,20,30,40 and
listB is having the following values 10,20,30
If listB contains listA elements i would like to enable particular controls if not i would like to disable the Controls
I tried of using two loops as follows
for(int ilist1=0;ilist1<listA.count;ilist1++)
{
for(int ilist2=0;ilist2<listB.count;ilist2++)
{
if(listA[ilist1]==listB[ilist2])
{
//Enable particular control
}
}
}
But i know this is not an appropriate one to do so can any one tell me the best approach to achieve this
What you want to do is to hash the items in the first list into a set then verify for each item in the second is within the set. Unfortunately the HashSet<> is not available so the closest you can get is the Dictionary<,>.
Do this:
Dictionary<string, string> set = new Dictionary<string, string>();
foreach (string item in listA)
{
set.Add(item, item);
}
foreach (string item in listB)
{
if (!set.ContainsKey(item))
{
//Enable particular control
}
}
It's easy by using the Intersect method:
if (listB.Intersect(listA).Count() > 0)
{
//enable Control
}
else
{
//disable control
}
I think you are looking for something like this
List<string> lista = new List<string>() {"10","40","30" };
List<string> listb = new List<string>() { "10", "20" };
var diff = listb.Except<string>(lista);
diff should give you the ones which didn't match else all would have been matched.
For 2.0
if (listb.TrueForAll(delegate(string s2) { return lista.Contains(s2); }))
MessageBox.Show("All Matched");
else
MessageBox.Show("Not Matched");
In fx 2.0, you can do it like this:
string b = listA.Find(delegate(string a) { return listB.Contains(a); });
if (string.IsNullOrEmpty(b))
{
//disable control
}
else
{
//enable control
}
Control.Enabled = listB.Intersect(listA).Any()
Note that Any() will only check to see if there is at least one item. Count() > 0 will evaluate the entire collection when you only need to check if there is at least one item
Edit: If you are in a .NET 2.0 environment then you can loop through and do this:
foreach (int item in listB)
{
if (listA.Contains(item))
return true;
}
return false;

Categories

Resources