I have a class as below
class MyClass
{
public string id { get; set; }
public string data { get; set; }
}
I have an array of ids I need to remove:
List<myClass> myObjArray = new List<myClass>;
myClass myObj1 = new myClass { id = "1", data = "aaa"};
myClass myObj2 = new myClass { id = "2", data = "bbb"};
myClass myObj3 = new myClass { id = "3", data = "ccc"};
myClass myObj4 = new myClass { id = "4", data = "ddd"};
myObjArray.Add(myObj1);
myObjArray.Add(myObj2);
myObjArray.Add(myObj3);
myObjArray.Add(myObj4);
string [] idToBeRemove = {"1", "3"};
Is there any method to remove the myObj in myObjArray where the id is in the idToBeRemove string?
List<T> has a method RemoveAll which will accomplish what you need. Unlike doing something like Where(...).ToList(), it will modify the existing list in place rather than create a new one.
myObjArray.RemoveAll(item => idToBeRemove.Contains(item.id));
Note that as your array of items to remove grows, you'll want to move to something more performant, such as a HashSet<T>, though with your current count of 2, it is not a pressing need.
#Richardissimo also offers a good suggestion in the comments to your question for when the main list itself grows, a Dictionary<K, V> could be useful. Again, not an immediate need with a small list, but something to keep in mind as it grows and if performance is an issue.
To remove from existing List you can use List.RemoveAll(Predicate):
myObjArray.RemoveAll(r => idToBeRemove.Contains(r.id));
To get result in new collection you can use Enumerable.Where and Enumerable.Contains:
var result = myObjArray.Where(m => !idToBeRemove.Contains(m.id)).ToList();
var result = myObjArray.Where(m => !idToBeRemove.Contains(m.id)).ToList();
foreach (var item in result)
{
myObjArray.Remove(item);
}
Use this to remove id:
myObjArray.RemoveAll(item => idToBeRemove.Contains(item.id));
Related
I have the same situation as this user how to use string.join to join value from an object array? in this question. However, I want to join all values from the object instead of only 1 value.
To recap my question:
I have an array of object e.g:
MyObject[] objs;
and within MyObject it contains 3 string property,
object[0].stringValue1
object[0].stringValue2
object[0].stringValue3
If I want to join the whole array of objects by all of their stringValues (stringValues1,2 and 3), how can I do it?
I think selector doesn’t allow me to select several elements, then how to use string.join to join several values from an object array?
See below for example usage of the two extension methods provided in the implementation section below. The first allows you to select the properties to include, and the second includes all string properties of the object in the source collection which I believe is the exact answer to your question.
Example Usage
Note, the resulting output from the two examples below are ordered differently as a result of how each implementation works, however the results are otherwise identical as a result of the first example specifying all string properties on the MyObj sample type
Live Fiddle Example
// Test Object
public class MyObj
{
public MyObj(string prop1, string prop2, string prop3)
{
Prop1 = prop1;
Prop2 = prop2;
Prop3 = prop3;
}
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
}
// Sample Data
var list = new List<MyObj> {
new MyObj("A1", "B1", "C1"),
new MyObj("A1", "B2", "C2"),
new MyObj("A3", "B3", "C3")
};
Samples using above object and data
// Example #1 - All properties separated by single separator
Console.WriteLine(list.Join(colSeparator: ','));
// RESULT: A1,A1,A3,B1,B2,B3,C1,C2,C3
// Example #2 - Object property separator, and different object separator
Console.WriteLine(list.Join(colSeparator: ',', rowSeparator: '\n'));
// RESULT: A1,B1,C1
A1,B2,C2
A3,B3,C3
Implementation
public static class EnumerableStringJoinExtension
{
public static string Join<T>(this IEnumerable<T> values, char colSeparator, char? rowSeparator = null)
{
var strProperties = typeof(T).GetProperties().Where(r=>r.PropertyType == typeof(string));
var sb = new StringBuilder();
foreach(var val in values)
sb.Append(string.Join(colSeparator, strProperties.Select(r=> r.GetValue(val)))).Append(rowSeparator ?? colSeparator);
sb.Remove(sb.Length - 1, 1);
return sb.ToString();
}
}
A possible way to solve it is to first create an array of each object's properties (using .Select()), and then flatten the resulting property arrays by using .SelectMany(). Both of those methods are found in the System.Linq namespace. The resulting IEnumerable<string> object's items can then be joined using string.Join().
If MyObject is defined as
class MyObject
{
public string First { get; set; }
public string Second { get; set; }
public string Third { get; set; }
}
and you define objects as
List<MyObject> objects = new()
{
new() { First = "ABC", Second = "DEF", Third = "GHI" },
new() { First = "JKL", Second = "MNO", Third = "PQR" },
new() { First = "STU", Second = "VWX", Third = "YZ" },
};
, a possible implementation is:
var flattenedObjects = objects
.Select(obj => new[] { obj.First, obj.Second, obj.Third })
.SelectMany(properties => properties);
var objectString = string.Join("_", flattenedObjects);
Printing the value of objectString to the console gives:
ABC_DEF_GHI_JKL_MNO_PQR_STU_VWX_YZ
Example fiddle here.
If you just want a one-line, handy C# without hard-coding property name you could try this:
string.Join("\n", objs.Select(o => string.Join("_", o.GetType().GetProperties().Select(p => p.GetValue(o)))));
This produces the following result:
"A_B_C\nD_E_F\nG_H_I"
with the object array as:
var objs = new MyObject[]
{
new MyObject("A", "B", "C"),
new MyObject("D", "E", "F"),
new MyObject("G", "H", "I")
};
But please note that if your class has properties in other types then you might need a Where() between GetProperties() and the second Select() to exclude unwanted properties.
How to add new element to 2d string array in c#?
Ex. I have a array
string [,] x = new string[,]{{"1","a"},{"2","b"}};
Now I want to increase the length array and add "3" and "c" to the top.
Array's are immutable in terms of length. Once defined, objects cannot be added into them.
You need a expandable collection for that like List of your custom class.
public class FooBar
{
public string Foo { get; set; }
public string Bar { get; set; }
}
and list like
var fooBars = new List<FooBar>
{
new FooBar() {Foo = "1", Bar = "a"},
new FooBar() {Foo = "2", Bar = "b"},
};
fooBars.Add(new FooBar() {Foo = "3", Bar = "c"});
Also you can now convert the collection to Array like this
var myArray = fooBars.ToArray();
You cannot resize Arrays in C#.
But there are 2 solutions for you:
Using List<T> https://msdn.microsoft.com/en-gb/library/6sh2ey19(v=vs.110).aspx
Recreate array everytime after add or remove operations(bad way).
P.S. It looks like you need a Dictionary<K,V> for your work(with unic 1st field, called Key).
https://msdn.microsoft.com/en-gb/library/xfhwa508(v=vs.110).aspx
var x = new List<List<string>>();
x.Add(new List<string>()
{
"1", "a"
});
// so on.
I have a list of the following class
class testdata {
public string code { get; set; }
public string[] values { get; set; }
}
how to perform join such that I get list of code and values, i.e values will repeat with every code, e.g if there are two items in list like
1."code1",{"value1","value2"}
2."code2",{"value1","value2","value3"}
I want the final to be in format like
Code1,Value1
code1,Value2
Code2,value1
code3,value2
code3,value3
I want to achieve it via LINQ and anonymous class, I am able to do it with loop and by creating a class as per final structure.
myList.SelectMany(td => td.values.Select(v => new { td.code, v } ))
SelectMany says "take many IEnumerables and concatenate their elements into a single IEnumerable"
td is a single element in your list. It is a single instance of testdata
So now you can do a Select over td.values to create the individual anonymous objects. Select will return an IEnumerable, but wrapped inside a SelectMany, many instances ofIEnumerable<anonymous object> will be flattened into a single IEnumerable<anonymous object>
Try this
List<TestData> testData = new List<TestData>() {
new TestData() { code = "Code1", values = new string[] {"Value1","Value2"}},
new TestData() { code = "Code2", values = new string[] {"value1"}},
new TestData() { code = "code3", values = new string[] {"value2","value3"}}
};
var results = testData.Select(x => x.values.Select(y => new { code = x.code, value = y })).SelectMany(y => y).ToList();
I am working on a project where I need to keep track of:
5-6 Root items of just a string name
Each root item need to have multiple children of different identifier types (int, string, float, etc). All the children of one root will be the same type but each root will have different children types
user will need to be able to add/delete children from each root
i will later need to access each children individually and perform string manipulations and parsing when needed
I've thought about maybe using a dictionary where the Key is a string and Values are lists of objects. Or having a unique class for each root item and each class will include a List of children.
Does anyone have any good suggestions? I'm still quite new to OOP, please bear with me :)
Thanks!
public interface IRoot {}
public class RootItem<T> : IRoot
{
public string Name { get; set; }
public List<T> Children {get; set; }
}
And then keep a Dictionary<string, IRoot> to hold them all.
Dictionary<string, IRoot> hair = new Dictionary<string, IRoot>();
hair.Add(
new RootItem<int>()
{
Name = "None",
Children = new List<int>() {1, 2, 3, 4}
}
);
hair.Add(
new RootItem<decimal>()
{
Name = "None",
Children = new List<decimal>() {1m, 2m, 3m, 4m}
}
);
How about a generic class with a List<T> to contain the children:
public class Root<T>
{
private List<T> children = null;
public Root(string name)
{
Name = name;
}
public string Name { get; set; }
public List<T> Children
{
get
{
if (children == null)
{
children = new List<T>();
}
return children;
}
}
}
Root<int> intRoot = new Root<int>("IntRoot");
intRoot.Children.Add(23);
intRoot.Children.Add(42);
Root<string> stringRoot = new Root<string>("StringRoot");
stringRoot.Children.Add("String1");
stringRoot.Children.Add("String2");
stringRoot.Children.Add("String3");
stringRoot.Children.Add("String4");
If you want to hold all the roots in one object, you could write your own class or use a Tuple:
var rootGroup = Tuple.Create(intRoot, stringRoot);
// intRoot is accessible as rootGroup.Item1
// stringRoot is accessible as rootGroup.Item2
Sounds like Dictionary<string, Tuple<type1, type 2, etc>> is a good candidate.
The key will be the string(root). The children to the root is a Tuple. We can add items to tuple. Thanks for pointing thisout.
Good starting point on Tuple
Here's one way to go about it. There's a lot of casting that needs to happen, but it gets the job done:
static void Main(string[] args)
{
Dictionary<string, IRootCollection> values = new Dictionary<string, IRootCollection>();
values["strings"] = new RootCollection<string>();
(values["strings"] as RootCollection<string>).Add("foo");
(values["strings"] as RootCollection<string>).Add("bar");
values["ints"] = new RootCollection<int>();
(values["ints"] as RootCollection<int>).Add(45);
(values["ints"] as RootCollection<int>).Add(86);
}
interface IRootCollection { }
class RootCollection<T> : List<T>, IRootCollection { }
I am using below code :
var list = new Collection<ArrayList>
{
new ArrayList
{
1,
"Test1"
},
new ArrayList
{
2,
"Test2"
},
};
In the above code I want to avoid the ArrayList and use the Generics. Is it possible in the above code?
Edit:
Above I have used only two values in one arraylist object, I may have multiple items of int's and string's in it.
You can't mix types in a generic list (unless the generic type is object, but that equates to ArrayList and is just a perversion of generics).
But you can create a class that contains a string and int and use that as the generic parameter for a generic list.
public class MyClass
{
public MyString string { get; set; }
public MyInt int { get; set; }
}
var list = new Collection<MyClass>
{
new MyClass { MyInt = 1, MyString = "Test1" },
new MyClass { MyInt = 2, MyString = "Test2" }
}
Another alternative, if using .NET 4.0 is to use a Tuple, though I would rather have a strongly typed class.
(untested code):
var list = new Collection<Tuple<int,string>>
{
Tuple.Create(1, "Test1"),
Tuple.Create(2, "Test2")
}
No.
The whole point of generics is that you can't put an int and a string in the same collection.
Instead, you should create your own class with int and string properties, then create a generic collection of that class.
Not really, the fact that you have different types makes using a generic pointless.
You could use List<object> instead of ArrayList but there's really no point. Instead you could create a custom class to hold the 2 values and use that in a generic type.
John
Maybe you need Dictionary?
var list = new Dictionary<int, string>
{
{ 1, "Test1" },
{ 2, "Test2" }
};
var list = new List < Dictionary<int, string>> ();
then you can populate it was data as you need.
I'm not sure what you are actually trying to achieve, but it seems to me you are trying to mimic the behavior of a dictionary or map, that can map two different values to each other. These values could be of any type you want.
Something like this:
Dictionary<int, string> d = new Dictionary<int, string>();
d.Add(1, "Test1");
d.Add(2, "Test2");
and you can handle your data as simple as:
string t1 = d[1]; //will hold "Test1"
string t2 = d[2]; //will hold "Test2"
Do you want something like this?