I have a List<T> where T has the property .Next.
The List has the following data:
One
Two
Three
Four
Five
I want to make this:
One.Next = Two;
Two.Next = Three;
Three.Next = Four;
Four.Next = Five;
Five.Next is null as its the last element
One should be assigned to a single Variable of the same type.
How can I do this without lots of ifs/while/hacks ?
UPDATE
The result variable should not be an anonymous type.
I need a return variable of the same type like IEnumerable> or List>
I forgot also to mention that I use an open generic type not a closed one.
sorry for the misinformation!
for(int i = 0;i < list.Count;++i)
list[i].Next = i < list.Count - 1 ? list[i + 1] : null;
You can either use a LinkedList as others have already suggested or ElementAtOrDefault:
var result = list.Select((s,i) => new { This=s, Next=list.ElementAtOrDefault(i+1) });
foreach(var x in result)
Console.WriteLine("{0}.{1}",x.This,x.Next);
Here's the demo: http://ideone.com/Qwiwc
The result variable should not be an anonymous type. I need a return
variable of the same type like IEnumerable> or List> I forgot also to
mention that I use an open generic type not a closed one.
Edit: Here's another approach using a IEnumerable<Tuple<T, T>>:
public static IEnumerable<Tuple<TSource, TSource>> ToLinkedSequence<TSource>(this IEnumerable<TSource> input)
{
return input.Select((x,i) => Tuple.Create(x, input.ElementAtOrDefault(i + 1)));
}
how you would use it:
var sequence = new[] { "One", "Two", "Three", "Four", "Five" };
var linkedSequence = sequence.ToLinkedSequence();
foreach (var x in linkedSequence)
Console.WriteLine("{0}.{1}", x.Item1, x.Item2);
Tuple Class
You can created a LinkedList
List<string> s = new List<string> {"one", "two", "three", "four", "five"};
LinkedList<string> ls = new LinkedList<string>(s);
If you do LinkedList.First you will get LinkedListNode that have the Next set as you desire
public interface INextable<T>
{
public T Next {get;set;}
}
List<MyClass> list = new List<MyClass>(); // Where MyClass implements INextable<MyClass>
var query = list.Zip(list.Skip(1), (a, b) => new
{
First = a,
Second = b
});
foreach (var item in query)
{
item.First.Next = item.Second;
}
Related
In the following code, I'm merging two arrays of types int and string. The first one's length is bigger than the second one, and as a result, the last index (which is 5) doesn't get merged:
int[] numbers = new[] { 1, 2, 3, 4, 5 };
string[] words = new string[] { "one", "two", "three", "four" };
var numbersAndWords = numbers.Zip(words, (n, w) => new { Number = n, Word = w });
foreach (var nw in numbersAndWords)
{
Console.WriteLine(nw.Number + nw.Word);
}
I would like to know a way of getting it merged. For example, creating a null or empty string after the last one that exists in words and using it to merge with the last numbers index. Couldn't figure it out.
Edit:
Result I get
1one
2two
3three
4four
Result I want
1one
2two
3three
4four
5
Thanks!
Edit: Not a duplicate, my other question is about calling method on a null object.
You can easily write your own LINQ-like extension method that will do it:
public static class MyEnumerable
{
public static IEnumerable<TResult> ZipWithDefault<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> selector)
{
bool firstMoveNext, secondMoveNext;
using (var enum1 = first.GetEnumerator())
using (var enum2 = second.GetEnumerator())
{
while ((firstMoveNext = enum1.MoveNext()) & (secondMoveNext = enum2.MoveNext()))
yield return selector(enum1.Current, enum2.Current);
if (firstMoveNext && !secondMoveNext)
{
yield return selector(enum1.Current, default(TSecond));
while (enum1.MoveNext())
{
yield return selector(enum1.Current, default(TSecond));
}
}
else if (!firstMoveNext && secondMoveNext)
{
yield return selector(default(TFirst), enum2.Current);
while (enum2.MoveNext())
{
yield return selector(default(TFirst), enum2.Current);
}
}
}
}
}
But if your source is always a pair of arrays, it might be easier to simply use for loop:
public static IEnumerable<TResult> ZipWithDefault<TFirst, TSecond, TResult>(this TFirst[] first, TSecond[] second, Func<TFirst, TSecond, TResult> selector)
{
var maxLength = Math.Max(first.Length, second.Length);
for(var i = 0; i < maxLength; i++)
{
var firstItem = i < first.Length ? first[i] : default(TFirst);
var secondItem = i < second.Length ? second[i] : default(TSecond);
yield return selector(firstItem, secondItem);
}
}
You can just extend the smaller of the two collections before zipping them up, e.g. something like this:
int[] numbers = new[] { 1, 2, 3, 4, 5 };
string[] words = new string[] { "one", "two", "three", "four" };
IEnumerable<string> wordsExtended = words;
if(words.Length < numbers.Length)
{
wordsExtended = words.Concat(Enumerable.Repeat("", numbers.Length - words.Length));
}
var numbersAndWords = numbers.Zip(wordsExtended, (n, w) => new { Number = n, Word = w });
foreach (var nw in numbersAndWords)
{
Console.WriteLine(nw.Number + nw.Word);
}
Ideally you want to wrap this up in a utility method and be generic so it works for any collections that are zipped.
Looks like someone wrote a generic implementation already on this Programmers StackExchange answer.
This is an asymmetric solution which uses the first sequence as an anchor, pairing corresponding elements from the second sequence when available, or a default value otherwise. No length calculation is required, nor early forced evaluation of enumerables.
Add an extension to IEnumerable:
public static class EnumerableExtensions {
public static IEnumerable<T> PadRight<T>(this IEnumerable<T> s)
{
foreach (var t in s)
yield return t;
while (true)
yield return default(T);
}
}
Use the extension to "pad" the second sequence before zipping:
int[] numbers = new[] { 1, 2, 3, 4, 5 };
string[] words = new string[] { "one", "two", "three", "four" };
var numbersAndWords = numbers.Zip(words.PadRight(), (n, w) => new { Number = n, Word = w });
foreach (var nw in numbersAndWords)
{
Console.WriteLine(nw.Number + nw.Word ?? string.Empty);
}
so I have a list:
["item1"]
["item2"]
["item3"]
and I want the list to be like this:
[""]
["item1"]
[""]
["item2"]
[""]
["item3"]
A simple back-to-front loop gives me just that:
for (int i = list.Count-1; i >= 0; i--)
list.Insert(i, string.Empty);
But I'm wondering if there is a more elegant way to do this with LINQ?
You could use an Intersperse extension method. That way, the meaning is clear and the code is reusable. Code taken from Extension method for Enumerable.Intersperse with slight modification to also include an empty string in the first position.
public static IEnumerable<T> Intersperse<T>(this IEnumerable<T> source, T element)
{
foreach (T value in source)
{
yield return element;
yield return value;
}
}
Here is a way to do it:
list = list.SelectMany(x => new [] { string.Empty, x }).ToList();
But it's worth noting that this creates unnecessary arrays.If your list is big enough that might be a problem. Instead I would create a new list with a capacity and populate it using loop:
var newList = new List<string>(list.Count * 2);
int j = 0;
for(int i = 0; i < list.Count * 2; i++)
newList.Add(i % 2 == 0 ? string.Empty : list[j++]);
This will avoid resizing the list each time you add or insert items.
You can do it using SelectMany LINQ extension:
void Main()
{
List<String> items = new List<String>()
{
"1",
"2",
"3"
};
var result = items
.SelectMany(item => new String[] {"Some value", item})
.ToList();
PrintItems(result);
}
void PrintItems<T>(IEnumerable<T> items)
{
foreach(var item in items)
{
Console.WriteLine(item);
}
}
But as you understand it is not the most effective way.
Another one-liner using Aggregate:
List<string> result = list.Aggregate(new List<string>(list.Count * 2), (a, x) => { a.Add(""); a.Add(x); return a; });
I want to compare two list of objects. These lists contains the same type of objects. I create a new List in my programme and i want to compare it at the old list which is in the database. I get it with a stored procedure, then i put it into an object.
The old list : the new list :
*Category 1* Category 5
*Category 2* Category 6
*Category 3* *Category 4*
Category 4
Here the aim is to delete the first three Category in the old list, beacause they don't exist in the new list. And to delete the Category 4 in the new list because category 4 already exists in the old list.
It is possible to use à method like Equals() or use two foreach loop to browse the lists ?
Thanks for you answers and advises
You can use the linq, except and where
var a = new List<string> { "a", "b", "c" };
var b = new List<string> { "c", "d", "e" };
var temp = a.Intersect(b).ToList();
b = b.Except(a).ToList();
a = temp;
Output:
a: "c"
b: "d", "e"
Note: It is probably more efficient to do this without linq
var a = new List<string> { "a", "b", "c" };
var b = new List<string> { "c", "d", "e" };
for(int i = 0; i < a.Count; i++)
if(b.Contains(a[i]))
b.Remove(a[i]);
else
a.Remove(a[i--]);
If you need to compare based on a particular value
for(int i = 0; i < a.Count; i++)
{
var obj = b.Where(item => item.Category == a[i].Category);
if(obj.Any())
b.Remove(obj.First());
else
a.Remove(a[i--]);
}
It's not the most pretty of implementations but the fastest way you can do this is:
var tempA = new HashSet<int>(inputA.Select(item => item.Id));
var tempB = new HashSet<int>(inputB.Select(item => item.Id));
var resultA = new List<Category>(inputA.Count);
var resultB = new List<Category>(inputB.Count);
foreach (var value in inputA)
if (tempB.Contains(value.Id))
resultA.Add(value);
foreach (var value in inputB)
if (!tempA.Contains(value.Id))
resultB.Add(value);
resultA.TrimExcess();
resultB.TrimExcess();
// and if needed:
inputA = resultA;
inputB = resultB;
If you need more than item.id as unique then use a new Tuple such as:
inputA.Select(item => new Tuple<int, string>(item.Id, item.Title));
Another option is to override .GetHashCode in your category class such as:
public override int GetHashCode()
{
return Id.GetHashCode();
}
public override bool Equals(object obj)
{
var typedObj = obj as Category;
if (typedObj == null)
return false;
return Title == typedObj.Title && Id == typedObj.Id && Rank == typedObj.Rank;
}
I would solve this by sorting the two list and iterating over the first and second list. I would compare the current item of the first list to the current item from the second. If a match is found I remove the match from the second list and I move to the next item in both lists, otherwise the current item of the first list is removed from it and the iteration continues in the first list.
Suppose I have two lists of strings, List1 and list2, where List1 is a property of an object of type Foo in a list fooList.
I would like to remove a given Foo if no string in foo.List1 matches any string in list2 a la RemoveAll.
I can do this with nested for loops, but is there a way to do this with a single slick LINQ expression?
Long-winded code, building a new list rather than removing stuff from the existing list:
var newFooList = new List<Foo>
foreach (Foo f in fooList)
{
bool found = false;
foreach (string s in newFooList)
{
if (f.FooStringList.Contains(s))
{
found = true;
break;
}
}
if (found)
newFooList.Add(f);
}
Yes:
var list2 = new List<string> { "one", "two", "four" };
var fooList = new List<Foo> {
new Foo { List1 = new List<string> { "two", "three", "five" } },
new Foo { List1 = new List<string> { "red", "blue" } }
};
fooList.RemoveAll( x => !x.List1.Intersect( list2 ).Any() );
Console.WriteLine( fooList );
Basically all the magic happens in RemoveAll: this only removes entries where the intersection of the entry's List1 property and list2 (i.e., the overlap) is empty.
I personally find the !....Any() construct kind of hard to read, so I like to have the following extension method on hand:
public static class Extensions {
public static bool Empty<T>( this IEnumerable<T> l,
Func<T,bool> predicate=null ) {
return predicate==null ? !l.Any() : !l.Any( predicate );
}
}
Then I can re-write the magic line in a way that's a little clearer:
fooList.RemoveAll( x => x.List1.Intersect( list2 ).Empty() );
I have an array of strings that I am looping through. I would like to loop through the array and on each iteration, create a new object with a name that matches the string value.
For example;
string[] array = new string[] { "one", "two", "three" };
class myClass(){
public myClass(){
}
}
foreach (string name in array)
{
myClass *value of name here* = new myClass();
}
Would result in three objects being instantiated, with the names "one", "two" and "three".
Is this possible or is there are better solution?
What are you trying to do is not possible in statically-typed language. IIRC, that's possible on PHP, and it's not advisable though.
Use dictionary instead: http://ideone.com/vChWD
using System;
using System.Collections.Generic;
class myClass{
public string Name { get; set; }
public myClass(){
}
}
class MainClass
{
public static void Main()
{
string[] array = new string[] { "one", "two", "three" };
IDictionary<string,myClass> col= new Dictionary<string,myClass>();
foreach (string name in array)
{
col[name] = new myClass { Name = "hahah " + name + "!"};
}
foreach(var x in col.Values)
{
Console.WriteLine(x.Name);
}
Console.WriteLine("Test");
Console.WriteLine(col["two"].Name);
}
}
Output:
hahah one!
hahah two!
hahah three!
Test
hahah two!
While others have given you an alternate but no one is telling why do they recommend you that.
That's because You cannot access object with dynamic names.
(Food for thought: Just think for a moment if you could do so, how will you access them before they are even coded/named.)
Instead create a Dictionary<string, myClass> as others mentioned.
Use a Dictionary<String, myClass> instead:
var dict= new Dictionary<String, myClass>();
foreach (string name in array)
{
dict.Add(name, new myClass());
}
Now you can access the myClass instances by your names:
var one = dict["one"];
or in a loop:
foreach (string name in array)
{
myClass m = dict[ name ];
}
You can use this approach:
var array = [srt1, srt2, str3];
var other_array = [];
for(var i = 0; i < array.length; i++){
other_array.push({
name: array[i]
})
}
And for lookup it is easy to find the instance you need by filtering:
var instance1 = other_array.filter(function(result) {
return result.name == 'str1';
});
Looks like you need a list of dictionary of your objects:
var myClassDictionary = new Dictionary<string,myClass>();
foreach (string name in array)
{
myClassDicationry.Add(name, new myClass());
}
// usage:
// myClass["one"] <- an instance of myClass
There are no programming languages that I know of that let you define variable names in runtime.
You could do something like this -
Dictionary<string, myClass> classes = new Dictionary<string, myClass>();
foreach(string name in array)
{
classes[name] = new myClass();
}
Then you can refer to the named instances later
classes[name].MyClassMethod();
You can use the following code.
string[] array = new string[] { "one", "two", "three" };
Dictionary<String, myClass> list;
class myClass(){
public myClass(){
list = new Dictionary<String, myClass>();
}
}
foreach (string name in array)
{
list.Add(name, new myClass())
}
You can use lists to store the objects so you can access them
list<myClass> myClasses = new List<myClass>();
foreach (myClass object in myClasses)
{
//preform interaction with your classes here
}
Not applicable to C#, or any statically-typed language for that matter.
For curiosity, I tried if what I remembered in PHP(creating variables on-the-fly) is still correct.
It's still the same PHP, last I used it was year 2000. You can generate variables on-the-fly, not saying it's advisable though, it pollutes the global variables, it can corrupt some existing variable or object with same name.
https://ideone.com/nJDiou
<?php
class MyClass
{
private $v;
function __construct($x) {
$this->v = $x;
}
public function getValue() {
return $this->v;
}
}
$one = new MyClass("I'm tough!");
echo "The one: " . $one->getValue() . "\n";
$i = 0;
foreach(array("one","two","three") as $h) {
$$h = new MyClass("Says who? " . ++$i);
}
echo "The one: " . $one->getValue() . "\n";
echo $two->getValue() . "\n";
echo $three->getValue() . "\n";
echo "loop\n";
foreach(array("three","one","two") as $h) {
echo $$h->getValue() . "\n";
}
?>
Outputs:
The one: I'm tough!
The one: Says who? 1
Says who? 2
Says who? 3
loop
Says who? 3
Says who? 1
Says who? 2