c# - index of array entries inside another array using LINQ - c#

I have an array of strings:
string[] stringArray = {"aaa", "bbb", "ccc", "aaa", "ccc", "ddd"};
I would like to get all indexes of this array where a substring of these strings are inside another array:
string[] searchArray = {"a","b"};
The answer I would like to get is then:
index = {0,1,3};
A soultion for just one entry of the searchArray would be:
List<int> index = stringArray.Select((s, i) => new { i, s })
.Where(t => t.s.Contains(searchArray[1]))
.Select(t => t.i)
.ToList();
A solution for all entries would be:
List<int> index = new List<int>();
foreach (string str in searchArray)
index.AddRange(stringArray.Select((s, i) => new { i, s })
.Where(t => t.s.Contains(str))
.Select(t => t.i)
.ToList());
index.Sort();
But out of curiosity, are there any solutions by just using one command in LINQ?

Yup, you just need Any to see if "any" of the target strings are contained in the array element:
List<int> index = stringArray
.Select((Value, Index) => new { Value, Index })
.Where(pair => searchArray.Any(target => pair.Value.Contains(target)))
.Select(pair => pair.Index)
.ToList();

Related

C# Linq Find all indexes of item in List<int> within another List<int>

I have a List looks like:
List<int> List1= new List<int>(){3,4,5};
and another looks like:
List<int> List2 = new List<int>(){1,2,3,4,5,6};
How can I use Linq to get an array of all of the indices of List1 from List2 like below:
var ResultList = {2,3,4};
var ResultList = List1.Select(x => List2.IndexOf(x));
This is a longer solution but prevents a nested loop through the array which may be faster if the arrays are huge (but slower if the arrays are small).
List<int> List1= new List<int>(){3,4,5};
List<int> List2 = new List<int>(){1,2,3,4,5,6};
var lookup = new Dictionary<int, int>();
for(var i=0; i<List2.Count; i++) {
lookup[List2[i]] = i;
}
List<int> Result = List1.Select(i => {
int index;
return lookup.TryGetValue(i, out index) ? index : -1;
}).ToList();
You can also do the overloaded version of Select statement to select the Value and return the Index:
var result = List2.Select((a, b) => new {Value = a, Index = b})
.Where(x => List1.Any(d => d == x.Value))
.Select(c => c.Index).ToArray();
If your List2 contains more than one instance of a List1 value (or Equality) type, then you can use the indexed overload of Select to find all the duplicates:
var List1= new List<int>(){3,4,5};
var List2 = new List<int>(){1,2,3,4,5,6,1,2,3,5};
var result = List2.Select((x, idx) => Tuple.Create(x, idx))
.Where(t => List1.Contains(t.Item1))
.Select(x => x.Item2)
// 2,3,4,8,9
or better, using C#7 Value Tuples
List2.Select((x, idx) => (X:x, Idx:idx))
.Where(t => List1.Contains(t.X))
.Select(x => x.Idx);
(.IndexOf returns just the first index found in the target)

How to convert IEnumerable<IEnumerable<IGrouping<int,string>>> to IEnumerable<IEnumerable<string>>

I'm trying to partition some comma separated lines into groups of size 2 at max.
How can i convert the collection of groups to list of lists as below?
I expect the partitions to be 3 first and then 4 after grouping.
List<string> chunk = new List<string>()
{
"a,b,c",
"a,d,e",
"b,c,d",
"b,e,d",
"b,f,g",
"e"
};
var partitons = chunk.GroupBy(c => c.Split(',')[0], (key, g) => g);
var groups = partitons.Select(x => x.Select((i, index) => new { i, index }).GroupBy(g => g.index / 2, e => e.i));
IEnumerable<IEnumerable<string>> parts = groups.Select(???)
This is what I wanted
var parts = groups.SelectMany(x => x).Select(y => y.Select(z => z));
Try this:
partitons = groups.Select(x => x.SelectMany(y => y));
I get this:

get indexes of different elements from arrays with equal length using Linq

I have two arrays with same length. for example
arr1 {1,2,3,4,5,6,7,8,9,0}.
arr2 {1,2,5,3,4,6,7,1,1,0}.
I need to get indexes of elements which are different:
{2,3,4,7,8}
How to do this using Linq?
The simplest I could think of:
int[] diff = Enumerable.Range(0, arr1.Length).Where(i => arr1[i] != arr2[i]).ToArray();
This should work:
int[] arr1 = new[] {1,2,3,4,5,6,7,8,9,0};
int[] arr2 = new[] {1,2,5,3,4,6,7,1,1,0};
var differentIndexes = arr2.Select((item, index) => new { item, index })
.Where(x => x.item != arr1[x.index])
.Select(x => x.index)
.ToArray();
You could use Enumerable.Zip() to walk the arrays in parallel, compare the values, then output matching sequence indices:
int [] arr1 = new int [] {1,2,3,4,5,6,7,8,9,0};
int [] arr2 = new int [] {1,2,5,3,4,6,7,1,1,0};
var query = arr1.Zip(arr2, (i, j) => i != j).Select((b, i) => b ? (int?)i : null).Where(iptr => iptr.HasValue).Select(iptr => (int)iptr);
Debug.WriteLine(JsonConvert.SerializeObject(query.ToList())); // outputs [2,3,4,7,8]
This doesn't require the sequences to be arrays.

Selecting array values from specific indexes order by index array

I want to select array values from specific indexes
Now I have this.
var xs = new[] { 11,12,13,14,15 };
var ind = new[] { 3,2,1,0 };
var results = xs.Where((x, idx) => ind.Contains(idx)).ToArray();
The result is {11,12,13,14}
However, I want my result to be ordered by index array which should be {14,13,12,11}
Thank you very much
var results = ind.Select(i => xs[i]).ToArray();
var array = xs.Zip(ind, (x, i) => new Tuple<int, int>(x, i))
.OrderBy(t => t.Item2)
.Select(t => t.Item1)
.ToArray();

Sort Descending directly

I have
List<string> strs;
double[] values;
where the values array contains the value of each of the string in strs list
Say strs={"abc","def","ghi"}
and values={3,1,2}
this means "abc" has value 3 and so on.
I wish to sort strs and values ordered by values, such that it becomes
strs={"def","ghi","abc"}
values={3,2,1}
I am using
string[] strsArr = strs.ToArray();
Array.Sort(values, strsArr);//1. sort it ascendingly
strs = strsArr.ToList();
Array.Reverse(strs);//2. reverse it
Is there a way I can sort it in descending sequence directly without 2 phases?
You can use a Dictionary and Linq to solve this.
var dict = new Dictionary<string, double>()
{
{"abc",3},
{"def",1},
{"ghi",2}
};
var sorted = dict.OrderByDescending(g => g.Value)
.Select(g => g.Key)
.ToArray();
Note, unless you have a ToArray() at the end the sorting will be deferred till later enumerated and may accidentally be enumerated multiple times.
How about this:
var strs = new [] { "abc", "def", "ghi", };
var values = new [] { 3, 1, 2, };
strs =
strs
.Zip(values, (s, v) => new { s, v })
.OrderByDescending(sv => sv.v)
.Select(sv => sv.s)
.ToArray();
try use dictionary:
Dictionary<string, double> dictionary = new Dictionary<string, double>();
dictionary.Add("abc", 3);
dictionary.Add("def", 1);
dictionary.Add("ghi", 2);
var sortedDict = dictionary.OrderByDescending(x => x.Value);
double[] values = sortedDict.Select(x => x.Value).ToArray();
List<string> strs = sortedDict.Select(x => x.Key).ToList();

Categories