Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I'm making a program to automate rolling initiative. I have most of it done, but I can't sort the outputs because it's a jagged array. I need the second column of each array in my jagged array to be sorted from highest to lowest.
using System;
using System.Linq;
namespace Auto_Initiative
{
class Program
{
static void Main(string[] args)
{
string[] encounter =
{
"Wizard", "18", "-2",
"Bard", "9", "3",
"Goblin 1", "16", "1",
"Goblin 2", "14", "1"
};
int[][] numbers = new int[encounter.Length / 3][];
int loop = 0;
for(int i = 0; i > encounter.Length; i += 3)
{
// Name number, real roll
numbers[loop] = new int[2] {i, Int32.Parse(encounter[i + 1]) + Int32.Parse(encounter[i + 2])};
}
Console.ReadKey();
}
}
}
One part of designing your software is choosing the right data structure for how you are planning to use it. Sometimes redundant data is required but we don't know what you are requirements are to make that decision. So as was mentioned by Sergey you should consider creating a custom class which I have shown an example of below. Also note that a string[] is not really a jagged array. By definition a jagged array has nested arrays of variable size. The data structure depicted above could be put in a regular string[][] and would not be jagged.
Object Oriented in Action
What you are looking for is stored in unitsSortedBySecondColumn.
class so65865986
{
static void Main(string[] args)
{
Encounter encounter = new Encounter
{
Units = new List<EncounterUnit> {
new EncounterUnit{
Name = "Wizard",
Column1 = 18,
Column2 = -2,
},
new EncounterUnit{
Name = "Bard",
Column1 = 9,
Column2 = 3,
},
new EncounterUnit{
Name = "Goblin 1",
Column1 = 16,
Column2 = 1,
},
new EncounterUnit{
Name = "Goblin 2",
Column1 = 14,
Column2 = 1,
},
},
};
var unitsSortedBySecondColumn = encounter.Units
.OrderBy(u => u.Column1)
.Select(u => new int[] { u.Column1, u.Column2 })
.ToArray();
}
}
class EncounterUnit
{
public string Name;
public int Column1; //Change name to whatever it means
public int Column2; //Change name to whatever it means
}
class Encounter
{
public List<EncounterUnit> Units;
}
Nested (but not Jagged) Array
class so65865986_nested_array
{
static void Main(string[] args)
{
string[][] encounter =
{
new string[] {"Wizard", "18", "-2" },
new string[] {"Bard", "9", "3" },
new string[] {"Goblin 1", "16", "1" },
new string[] {"Goblin 2", "14", "1" },
};
int[][] numbers = encounter
.Select(u => new int[] { int.Parse(u[1]), int.Parse(u[2]) })
.OrderBy(u => u[0])
.ToArray();
Console.ReadKey();
}
}
Other Notes
Also, another note. You don't need to use Int32 because it is recommended you use the aliases provided which in this case is int.
use this code:
string[] encounter =
{
"Wizard", "18", "-2",
"Bard", "9", "3",
"Goblin 1", "16", "1",
"Goblin 2", "14", "1"
};
int[,] numbers = new int[encounter.Length / 3, 3];
for (int i = 1; i < encounter.Length / 4; i++)
{
for (int j = 0; j < encounter.Length / 3; j += 1)
{
numbers[j, i] = Convert.ToInt32(encounter[i + (j * 3)]);
Console.Write(numbers[j, i] + " ");
}
Console.WriteLine(Environment.NewLine);
}
Console.ReadLine();
I have data table having rows like
ID Name
2 A
4 B
3 C
5 D
1 E
List order = new List() { "1", "3", "2", "5", "4" }
--------------order by list-----------------
ID Name
1 E
3 C
2 A
5 D
4 B
can anyone help to implement this.. I am using DataTable in Winforms.
Another solution to the already given ones, would be to loop your order list and then sort your source list.
// source list
List<Foo> lSource = new List<Foo>() {
new Foo() { ID = 2, Name = "A" },
new Foo() { ID = 4, Name = "B" },
new Foo() { ID = 3, Name = "C" },
new Foo() { ID = 5, Name = "D" },
new Foo() { ID = 1, Name = "E" },
};
// order list
List<int> order = new List<int>() { 1, 3, 2, 5, 4 };
// loop order list and sort source list
order.ForEach(x =>
{
lSource = lSource.OrderBy(g => g.ID == x).ToList();
});
// set datasource
dataGridView1.DataSource = lSource;
I just added a class Foo containing an int ID and a string Name, because you didn't share your whole code.
I think you can join your order and your datatable with AsEnumerable method and on on part you can equalize both of them and select rows, then you can generate a DataTable from that query with CopyToDataTable method.
var dt = new DataTable();
var dc = new DataColumn() { ColumnName = "ID", DataType = typeof(string) };
dt.Columns.Add(dc);
dc = new DataColumn() { ColumnName = "Name", DataType = typeof(string) };
dt.Columns.Add(dc);
dt.Rows.Add(new object[] { "2", "A" });
dt.Rows.Add(new object[] { "4", "B" });
dt.Rows.Add(new object[] { "3", "C" });
dt.Rows.Add(new object[] { "5", "D" });
dt.Rows.Add(new object[] { "1", "E" });
List<string> order = new List<string>() { "1", "3", "2", "5", "4" };
var query = from item in order
join row in dt.AsEnumerable() on item equals row.Field<string>("ID")
select row;
var result = query.CopyToDataTable();
result will be;
I'm not sure this is the best way or not but this seems to fit with your case.
You can join both lists (the one with items and the one with sorted id's) and then select the items:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var list = new List<Item>{
new Item { Id = 2, Text = "A" },
new Item { Id = 4, Text = "B" },
new Item { Id = 3, Text = "C" },
new Item { Id = 5, Text = "D" },
new Item { Id = 1, Text = "E" }
};
var sortorder = new List<int> { 1, 3, 2, 5, 4 };
var sortedlist = sortorder.Join(list, x => x, y => y.Id, (x,y) => y);
foreach(var item in sortedlist)
Console.WriteLine("{0} {1}", item.Id, item.Text);
}
}
How can I create a list with a fixed set of entries.
Learning C# and doing an exercise to list all cards in a deck of cards(without jokers). Going to use two foreach loops to print them out.
However I cannot get a default list of the cards(I am overloading the method). Looking at the docs http://msdn.microsoft.com/en-us/library/6sh2ey19(v=vs.110).aspx and some examples http://www.dotnetperls.com/list and each element is added in individually.
// from dotnet perls
class Program
{
static void Main()
{
List<string> dogs = new List<string>(); // Example List
dogs.Add("spaniel"); // Contains: spaniel
dogs.Add("beagle"); // Contains: spaniel, beagle
dogs.Insert(1, "dalmatian"); // Contains: spaniel, dalmatian, beagle
foreach (string dog in dogs) // Display for verification
{
Console.WriteLine(dog);
}
}
}
I have tried both the Add and Insert methods but cannot create my lists.
// my code
using System;
using System.Collections.Generic;
using System.Linq;
class Deck
{
static void Main()
{
List<string> deck = new List<string>();
deck.Insert("Ace", 2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King");
List<string> colour = new List<string>();
colour.Add("Hearts", "Diamonds", "Spades", "Clubs");
foreach (string card in deck)
{
foreach(string suit in colour)
{
Console.Write(colour + " " + card);
}
}
}
}
List.Add or List.Insert doesn't take variable length parameters. You may need to use List.AddRange method.
List<string> deck = new List<string>();
deck.AddRange(new []{"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"});
List<string> colour = new List<string>();
colour.AddRange(new []{"Hearts", "Diamonds", "Spades", "Clubs"});
Also note that I've converted the numerical parameters to string as the list is List<string>, otherwise it won't compile.
I love tuples. They allow you to quickly group relevant information together without having to write a struct or class for it. This is very useful while refactoring very localized code.
Initializing a list of them however seems a bit redundant.
var tupleList = new List<Tuple<int, string>>
{
Tuple.Create( 1, "cow" ),
Tuple.Create( 5, "chickens" ),
Tuple.Create( 1, "airplane" )
};
Isn't there a better way? I would love a solution along the lines of the Dictionary initializer.
Dictionary<int, string> students = new Dictionary<int, string>()
{
{ 111, "bleh" },
{ 112, "bloeh" },
{ 113, "blah" }
};
Can't we use a similar syntax?
c# 7.0 lets you do this:
var tupleList = new List<(int, string)>
{
(1, "cow"),
(5, "chickens"),
(1, "airplane")
};
If you don't need a List, but just an array, you can do:
var tupleList = new(int, string)[]
{
(1, "cow"),
(5, "chickens"),
(1, "airplane")
};
And if you don't like "Item1" and "Item2", you can do:
var tupleList = new List<(int Index, string Name)>
{
(1, "cow"),
(5, "chickens"),
(1, "airplane")
};
or for an array:
var tupleList = new (int Index, string Name)[]
{
(1, "cow"),
(5, "chickens"),
(1, "airplane")
};
which lets you do: tupleList[0].Index and tupleList[0].Name
Framework 4.6.2 and below
You must install System.ValueTuple from the Nuget Package Manager.
Framework 4.7 and above
It is built into the framework. Do not install System.ValueTuple. In fact, remove it and delete it from the bin directory.
note: In real life, I wouldn't be able to choose between cow, chickens or airplane. I would be really torn.
Yes! This is possible.
The { } syntax of the collection initializer works on any IEnumerable
type which has an Add method with the correct amount of arguments.
Without bothering how that works under the covers, that means you can
simply extend from List<T>, add a custom Add method to initialize your
T, and you are done!
public class TupleList<T1, T2> : List<Tuple<T1, T2>>
{
public void Add( T1 item, T2 item2 )
{
Add( new Tuple<T1, T2>( item, item2 ) );
}
}
This allows you to do the following:
var groceryList = new TupleList<int, string>
{
{ 1, "kiwi" },
{ 5, "apples" },
{ 3, "potatoes" },
{ 1, "tomato" }
};
C# 6 adds a new feature just for this: extension Add methods. This has always been possible for VB.net but is now available in C#.
Now you don't have to add Add() methods to your classes directly, you can implement them as extension methods. When extending any enumerable type with an Add() method, you'll be able to use it in collection initializer expressions. So you don't have to derive from lists explicitly anymore (as mentioned in another answer), you can simply extend it.
public static class TupleListExtensions
{
public static void Add<T1, T2>(this IList<Tuple<T1, T2>> list,
T1 item1, T2 item2)
{
list.Add(Tuple.Create(item1, item2));
}
public static void Add<T1, T2, T3>(this IList<Tuple<T1, T2, T3>> list,
T1 item1, T2 item2, T3 item3)
{
list.Add(Tuple.Create(item1, item2, item3));
}
// and so on...
}
This will allow you to do this on any class that implements IList<>:
var numbers = new List<Tuple<int, string>>
{
{ 1, "one" },
{ 2, "two" },
{ 3, "three" },
{ 4, "four" },
{ 5, "five" },
};
var points = new ObservableCollection<Tuple<double, double, double>>
{
{ 0, 0, 0 },
{ 1, 2, 3 },
{ -4, -2, 42 },
};
Of course you're not restricted to extending collections of tuples, it can be for collections of any specific type you want the special syntax for.
public static class BigIntegerListExtensions
{
public static void Add(this IList<BigInteger> list,
params byte[] value)
{
list.Add(new BigInteger(value));
}
public static void Add(this IList<BigInteger> list,
string value)
{
list.Add(BigInteger.Parse(value));
}
}
var bigNumbers = new List<BigInteger>
{
new BigInteger(1), // constructor BigInteger(int)
2222222222L, // implicit operator BigInteger(long)
3333333333UL, // implicit operator BigInteger(ulong)
{ 4, 4, 4, 4, 4, 4, 4, 4 }, // extension Add(byte[])
"55555555555555555555555555555555555555", // extension Add(string)
};
C# 7 will be adding in support for tuples built into the language, though they will be of a different type (System.ValueTuple instead). So to it would be good to add overloads for value tuples so you have the option to use them as well. Unfortunately, there are no implicit conversions defined between the two.
public static class ValueTupleListExtensions
{
public static void Add<T1, T2>(this IList<Tuple<T1, T2>> list,
ValueTuple<T1, T2> item) => list.Add(item.ToTuple());
}
This way the list initialization will look even nicer.
var points = new List<Tuple<int, int, int>>
{
(0, 0, 0),
(1, 2, 3),
(-1, 12, -73),
};
But instead of going through all this trouble, it might just be better to switch to using ValueTuple exclusively.
var points = new List<(int, int, int)>
{
(0, 0, 0),
(1, 2, 3),
(-1, 12, -73),
};
You can do this by calling the constructor each time with is slightly better
var tupleList = new List<Tuple<int, string>>
{
new Tuple<int, string>(1, "cow" ),
new Tuple<int, string>( 5, "chickens" ),
new Tuple<int, string>( 1, "airplane" )
};
Old question, but this is what I typically do to make things a bit more readable:
Func<int, string, Tuple<int, string>> tc = Tuple.Create;
var tupleList = new List<Tuple<int, string>>
{
tc( 1, "cow" ),
tc( 5, "chickens" ),
tc( 1, "airplane" )
};
Super Duper Old I know but I would add my piece on using Linq and continuation lambdas on methods with using C# 7. I try to use named tuples as replacements for DTOs and anonymous projections when reused in a class. Yes for mocking and testing you still need classes but doing things inline and passing around in a class is nice to have this newer option IMHO. You can instantiate them from
Direct Instantiation
var items = new List<(int Id, string Name)> { (1, "Me"), (2, "You")};
Off of an existing collection, and now you can return well typed tuples similar to how anonymous projections used to be done.
public class Hold
{
public int Id { get; set; }
public string Name { get; set; }
}
//In some method or main console app:
var holds = new List<Hold> { new Hold { Id = 1, Name = "Me" }, new Hold { Id = 2, Name = "You" } };
var anonymousProjections = holds.Select(x => new { SomeNewId = x.Id, SomeNewName = x.Name });
var namedTuples = holds.Select(x => (TupleId: x.Id, TupleName: x.Name));
Reuse the tuples later with grouping methods or use a method to construct them inline in other logic:
//Assuming holder class above making 'holds' object
public (int Id, string Name) ReturnNamedTuple(int id, string name) => (id, name);
public static List<(int Id, string Name)> ReturnNamedTuplesFromHolder(List<Hold> holds) => holds.Select(x => (x.Id, x.Name)).ToList();
public static void DoSomethingWithNamedTuplesInput(List<(int id, string name)> inputs) => inputs.ForEach(x => Console.WriteLine($"Doing work with {x.id} for {x.name}"));
var namedTuples2 = holds.Select(x => ReturnNamedTuple(x.Id, x.Name));
var namedTuples3 = ReturnNamedTuplesFromHolder(holds);
DoSomethingWithNamedTuplesInput(namedTuples.ToList());
One technique I think is a little easier and that hasn't been mentioned before here:
var asdf = new [] {
(Age: 1, Name: "cow"),
(Age: 2, Name: "bird")
}.ToList();
I think that's a little cleaner than:
var asdf = new List<Tuple<int, string>> {
(Age: 1, Name: "cow"),
(Age: 2, Name: "bird")
};
var colors = new[]
{
new { value = Color.White, name = "White" },
new { value = Color.Silver, name = "Silver" },
new { value = Color.Gray, name = "Gray" },
new { value = Color.Black, name = "Black" },
new { value = Color.Red, name = "Red" },
new { value = Color.Maroon, name = "Maroon" },
new { value = Color.Yellow, name = "Yellow" },
new { value = Color.Olive, name = "Olive" },
new { value = Color.Lime, name = "Lime" },
new { value = Color.Green, name = "Green" },
new { value = Color.Aqua, name = "Aqua" },
new { value = Color.Teal, name = "Teal" },
new { value = Color.Blue, name = "Blue" },
new { value = Color.Navy, name = "Navy" },
new { value = Color.Pink, name = "Pink" },
new { value = Color.Fuchsia, name = "Fuchsia" },
new { value = Color.Purple, name = "Purple" }
};
foreach (var color in colors)
{
stackLayout.Children.Add(
new Label
{
Text = color.name,
TextColor = color.value,
});
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
}
this is a Tuple<Color, string>