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.
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.
As we know that a simple array can be initialized like this for example, int [] TestArray = {1,2,3,4}, but how about if we use an array with a structure object and we want to initialize it?
I know that we can access the structure object array like this for example,
Suppose struct Automobile is our structure and we have field in it such as public int year , public string model and we create an array structure object for example, Automobile [] Car = new Automobile(); so we can access the element of a structure array object and give it a value if we use it with structure field for example, Car[2].year = "2016"and then can display it in for example,
MessageBox.Show(Car[2].year.ToString());
But what if we want our structure array object to having initial values like we have it in normal array initialization as written in the start?
Try
var auto = new[]
{
new Automobile {year = 1984, model = "charger"},
new Automobile {year = 1985, model = "challenger"},
new Automobile {year = 1984, model = "hemicuda"}
};
var auto = new[] is shorthand for Automobile[] auto = new Automobile[] which you can use instead if you're more comfortable with it.
Let the Structure be defined as like this:
public struct Automobile
{
public int Year { get; set; }
public string model { get; set; }
}
Then you can create the array of this structure variables like the following:
Automobile[] AutomobileList = new Automobile[] {
new Automobile() {Year=2015,model="Some model1" },
new Automobile() {Year=2014,model="Some model2" },
new Automobile() {Year=2013,model="Some model3" }};
Similar way you can define a list too;
List<Automobile> AutomobileList = new List<Automobile>() {
new Automobile() {Year=2015,model="Some model1" },
new Automobile() {Year=2014,model="Some model2" },
new Automobile() {Year=2013,model="Some model3" }};
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?
I have a simple class which has boolean field:
public struct Foo { bool isAvailable; }
Now I have a List of foos:
List < Foo > list = new List< Foo >();
Later on I enumerate each foo in the list and try to update its isAvailable field:
foreach(Foo foo in list) {
foo.isAvailable = true;
}
But the above code never updates the list. What am I doing wrong here and what's its remedy.
It's because Foo is a mutable struct.
When you fetch the value from the list, it's making a copy - because that's how value types behave. You're changing the copy, leaving the original value unchanged.
Suggestions:
You probably should be using a class
Don't create mutable structs. They behave in ways which can be hard to predict, or at least not the way you might expect when you're not explicitly thinking about it.
While you could change your code to iterate over the list in a different way and replace the value each time, it's generally a bad idea to do so. Just use a class... or project your list to a new list with the appropriate values.
Original answer, when Foo was a class
It should work fine. For example, here's a short but complete program which does work:
using System.Collections.Generic;
public class Foo
{
public bool IsAvailable { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name + ": " + IsAvailable;
}
}
class Test
{
static void Main()
{
List<Foo> list = new List<Foo>()
{
new Foo { Name = "First", IsAvailable = true },
new Foo { Name = "Second", IsAvailable = false },
new Foo { Name = "Third", IsAvailable = false },
};
Console.WriteLine("Before:");
list.ForEach(Console.WriteLine);
Console.WriteLine();
foreach (Foo foo in list)
{
foo.IsAvailable = true;
}
Console.WriteLine("After:");
list.ForEach(Console.WriteLine);
}
}
Try to adapt your current code to a similar short but complete program which doesn't work, post that, and we can work out what's going on.
You're using a struct as Foo, not a class. Structs are copied, not referenced, and therefore you only modify the copy and not the object stored in the list.
So you basically have two options:
Make it a class
Re-assign the result to the list. To do so, I'd iterate using an index instead of using foreach.
When you fill list, you need to create new istance for each Foo Class.
List list = new List();
Foo foo = new Foo();
foo.isAvailable = false;
list.Add(foo);
foo = new Foo();
list.Add(foo);
foo = new Foo();
list.Add(foo);
if you fill on this way:
List list = new List();
Foo foo = new Foo();
list.Add(foo);
list.Add(foo);
list.Add(foo);
you are reference on same memory location on stack for each object.
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));