LINQ - Find item index in listbox - c#

I using this code to get item index in listbox:
string searchfor = "B";
for (int i = 0; i < listBox1.Items.Count; i++)
{
listBox1.SelectedIndex = i;
if (searchfor == listBox1.Text)
Console.WriteLine(listBox1.SelectedIndex);
}
List items:
A
B => 1
F
E
R
B => 5
Y
B => 7
G
B => 8
Can anyone help me to do it with linq?

You can use the overload of Select that includes the item's index:
listBox1.Items
.Select((item, index) => new {item, index})
.Where(ix => ix.item == searchFor)
.Select(ix => ix.index);

string searchfor = "B";
var Items = listbox1.Items.Where( item => item.Text == searchfor);
//in case there are more than 1
Items.ForEach( i => Console.WriteLine(i.SelectedIndex))
or
string searchfor = "B";
var Item = listbox1.Items.FirstOrDefault( item => item.Text == searchfor);
Console.WriteLine(Item.SelectedIndex);

this should work as well:
listBox1.Items.Where(item=> item.Text == searchfor)
.ForEach(i => Console.WriteLine(listBox1.Items.IndexOf(i)));

Related

Rename the Repeated Values in array c#

I have a array which looks like this :-
a[53]={ARPNUM-T,
OR1PATTYP-T,
IVNUM-T,
IVDESC-T,
ORDEPT-T,
ARPNAME-T,
ARGNAME-T,
ARPATADDR1-T,
ARPATCITY-T,
ARPATSTATE-T,
ARPATZIP-N,
ARSEX-T,
ARBIRTH-N,
ARSSN-T,
ARMARRY-T,
ARADMDT-N,
ARDISDT-N,
ARPEMP-T,
ARPHY1-T,
ARPHYNM1-T,
ARMRNUM-T,
ARGUARSSN-T,
ARPHONE-T,
AREMPLYR-T,
ARADDR1-T,
ARSTATE-T,
ARZIP-N,
ARPATPHONE-N,
ARDIAG01-T,
ISSUBNAME-T,
ISCOMPCD-T,
ISCONAME-T,
ISCONTRAC-T,
ISGROUP-T,
ISPRIMARY-T,
ISCOADDR-N,
ISCOCITST-T,
ISPATREL-T,
ISCERTNO-T,
ISCOZIP-N,
ISSUBNAME-T,
ISCOMPCD-T,
ISCONAME-T,
ISCONTRAC-T,
ISGROUP-T,
ISPRIMARY-T,
ISCOADDR-N,
ISCOCITST-T,
ISPATREL-T,
ISCERTNO-T,
ISCOZIP-N,
ARCITY-T}
There are some repeated values like ISSUBNAME-T,ISCOMPCD-T.
i need to fill the array a to array b
where repeated value will be suffixed by the number of times of repetition ,
For eg - if ISSUBNAME-T is repeated 3 times then ISSUBNAME-T_3 .
I have tried a code:-
for (int d = 1; d < 53; d++)
{
b[0] = a[0];
for (int k = 1; k < d; k++)
{
int count = 0;
//b[d] = a[d];
if (a[d] == a[d - k])
{
count++;
if (count > 0)
{
b[d] = a[d] + "_" + count + "";
}
else
{
b[d] = a[d];
}
//Console.WriteLine(count);
}
//Console.WriteLine(count);
}
//Console.WriteLine(count);
}
But it's not showing correct output.
Group array items by their values. Then check if group contains more than one item. If so, then return formatted item value, otherwise simply return item value:
string[] b = a.GroupBy(i => i)
.Select(g => g.Count() > 1 ?
String.Format("{0}_{1}", g.Key, g.Count()) : g.Key)
.ToArray();
Query syntax (easily allows to calculate group length only once):
var query = from i in a
group i by i into g
let count = g.Count()
select count > 1 ? String.Format("{0}_{1}", g.Key,count) : g.Key;
string[] b = query.ToArray();
UPDATE: If you want to keep all items and have incremental suffixes
string[] b = a.GroupBy(e => e)
.SelectMany(g => g.Count() == 1 ?
g.Take(1) :
g.Select((e,i) => String.Format("{0}_{1}", e,i+1))
.ToArray();
UPDATE 2: If you want also preserving original order, then simple loop and dictionary will be simpler
string[] b = new string[a.Length];
var duplicatedItems = a.GroupBy(a => a)
.Where(g => g.Count() > 0)
.ToDictionary(g => g.Key, g => g.Count());
for(int i = b.Length - 1; i >= 0 ; i--)
{
string item = a[i];
if (!duplicatedItems.ContainsKey(item))
{
b[i] = item;
continue;
}
b[i] = String.Format("{0}_{1}", item, duplicatedItems[item]);
duplicatedItems[item]--;
}
Linq query for comparison
string[] b =
a.Select((e,i) => new { Item = e, Index = i })
.GroupBy(x => x.Item)
.SelectMany(g => g.Count() == 1 ?
g.Take(1) :
g.Select((x,i) => new {
Item = String.Format("{0}_{1}", x.Item, i+1),
Index = x.Index
}))
.OrderBy(x => x.Index)
.Select(x => x.Item)
.ToArray();

Fetch (x,y) from a 2D Array where condition matches

This is 2D array:
int[][] array2D = new int[7][];
for (int i = 0; i < 7; i++)
array2D[i] = new int[7];
How can I turn the following into a LINQ query, or use enumerable methods to achieve the same output?
var lst = new List<Point>();
for (int r = 0; r < array2D.Length; r++)
for (int c = 0; c < array2D[r].Length; c++)
if (array2D[r][c] == 0)
lst.Add(new Point(c, r));
EDIT - Solution based on #'King King's answer
var lst = m_boardArr.SelectMany((row, rowIndex) =>
row.Select((val, colIndex) =>
new { val, point = new Point(colIndex, rowIndex) })
.Where(col => col.val == 0)
.Select(col => col.point)).ToList();
Try this:
var lst = array2D.SelectMany((x,r) => x.Select((a,c)=> new {a,b=new Point(c,r)})
.Where(a=>a.a==0)
.Select(a=>a.b)).ToList();
The trick is to use the Select and SelectMany that capture the loop variables into an anonymous type, then get those properties back later after the Where clause, thus:
var list = array2D
.SelectMany((row, r) => row
.Select((el, c) =>
new {Element = el, ColIndex = c, RowIndex = r})
.Where(thing => thing.Element == 0)
.Select(thing => new Point(thing.RowIndex, thing.ColIndex)))
.ToList();
EDIT: Bartosz's comment applies to this solution as well. Unreadable!
var lst = array2D
.SelectMany((innerArray, r)
=> Enumerable
.Range(0, innerArray.Length)
.Where(c => innerArray[c] == 0)
.Select(c => new Point(c, r)))
.ToList();
However, your current solution is more readable.

Aggregate function Count() using dynamic linq query

I am trying to use Aggregate function Count() on some column using dynamic linq query but I am not able to achieve, what I am exactly looking is
Select Count(Id),Id
from Table1
Group By Id
Having Count(Id) > 1
I want to convert the same query to dynamic linq query, any suggestions on how to achieve this?
Stolen from here:
var distinctItems =
from list in itemsList
group list by list.ItemCode into grouped
where grouped.Count() > 1
select grouped;
The following two queries will give you the exact same result:
first with lambda second result without.
var Table1 = new List<Row>();
for (int i = 0; i < 10; i++)
{
for (int m = 0; m < 5; m++)
{
for (int x = 0; x < i + m; x++)
{
Table1.Add(new Row() { Id = m });
}
}
}
var result = Table1.GroupBy(row => row.Id)
.Where(p => p.Count() > 1);
var resultB = from row in Table1
group row by row.Id into rowGrouped
where rowGrouped.Count() > 1
select rowGrouped;
foreach (var r in resultB)
{
Console.WriteLine("ID {0} count: {1}", r.Key, r.Count());
}
May be something like this
list.GroupBy(item => item.Id)
.Where(group => group.Count() > 1)
.Select(group => new {
Id = group.Key,
Count = group.Count() });

how can i count duplicates in a list and change the item value

I have a program that generates 3 lists based on the contents of a text file. Now I want to look at a list and if there's an item in it more than once, I'd like to change the value to "number in list x item" and remove the duplicates from the list.
Here is the code I use to open and split up the file into the lists:
private void open_Click(object sender, EventArgs e)
{
if (inputFile.ShowDialog() == DialogResult.OK)
{
var reader = new StreamReader(File.OpenRead(inputFile.FileName));
while (!reader.EndOfStream)
{
string line = reader.ReadLine();
if (string.IsNullOrEmpty(line)) continue;
if (line.StartsWith("#main"))
{
deck = "main";
}
if (deck == "main")
{
if (!line.StartsWith("#"))
{
int cardid = Convert.ToInt32(line.Substring(0));
MainDeck.Items.Add(Program.CardData[cardid].Name);
}
}
if (line.StartsWith("#extra"))
{
deck = "extra";
}
if (deck == "extra")
{
if (!line.StartsWith("#extra") && !line.StartsWith("!side"))
{
int cardid = Convert.ToInt32(line.Substring(0));
ExtraDeck.Items.Add(Program.CardData[cardid].Name);
}
}
if (line.StartsWith("!side"))
{
deck = "side";
}
if (deck == "side")
{
if (!line.StartsWith("!side"))
{
int cardid = Convert.ToInt32(line.Substring(0));
SideDeck.Items.Add(Program.CardData[cardid].Name);
}
}
}
reader.Close();
GenerateCode();
}
}
In other words say the item "hello" is in the list 3 times: I want to change it to be in the list only once and say "3x hello".
Use Enumerable.Distinct to remove the duplicates:
MainDeck = MainDeck.Distinct().ToList();
ExtraDeck = ExtraDeck.Distinct().ToList();
SideDeck = SideDeck.Distinct().ToList();
If you want to count the duplicates first:
int mainDeckDups = MainDeck.Count - MainDeck.Distinct().Count();
int extraDeckDups = ExtraDeck.Count - ExtraDeck.Distinct().Count();
int sideDeckDups = SideDeck.Count - SideDeck.Distinct().Count();
If you really want to show how many times an item was in the list you could use Enumerable.GroupBy, e.g.:
var mainDeckGroups = MainDeck.GroupBy(s => s)
.Select(g => new { Item = g.Key, Count = g.Count() })
.Where(x => x.Count > 1)
.OrderByDescending(x => x.Count);
foreach (var dup in mainDeckGroups)
Console.WriteLine("{0}x {1}", dup.Count, dup.Item);
// other lists ...
Something like:
var g = MainDeck.Items.GroupBy(i => i).Select(x => x.Count() +"x " + x.Key);
You can filter it out if you want to count only the word "main" there. Follow the same for other lists..
The query is not evaluated at that point. Do a .ToList() or .ToArray() to let that happen on g.
If you want to preserve order of items in the list (assuming list contains the possible duplicates)
var data = list.Select(r => result.Count(i => i == r) + "x " + r).ToList();
and just slightly modify it to have "Hello" instead of "1x Hello".
You can try it as well.
var list = new List<string> { "Hello", "World", "Hello", "Great", "World" };
var query = list.GroupBy(s => s)
.Select(g => new { Value = g.Key, Count = g.Count() });
Then,
var resultList = query.Select(result => string.Format("{0}x {1}", result.Count, result.Value)).ToList();
or above code can be replaced as below for more clarity
foreach (var result in query)
resultList.Add(string.Format("{0}x {1}", result.Count, result.Value));
Hope it helps.

Grouping each 500 elements of array according to array elements

I have an array of 2000 strings. The strings are: "art", "economy", "sport" and "politic". I want to group each 500 elements and get their counts
Could anyone help please?
Another solution:
var count = 0;
var dictionaries =
strings.GroupBy(s => count++ / 500)
.Select(g => g.Distinct().ToDictionary(k => k, k => g.Count(s => s == k)))
.ToList();
This will create a List<Dictionary<string, int>>. Each dictionary represents a tally of 500 elements (or possibly less for the last dictionary), where the keys are strings and the values are the number of occurrences of the string among the 500 elements the dictionary represents.
There is no requirement to hardcode all the possible values that may be encountered.
For the maximum possible performance you can also use this version:
var count = 0;
var dictionaries =
strings.GroupBy(s => count++ / 500)
.Select(g => g.Aggregate(
new Dictionary<string, int>(),
(d, w) => { d[w] = (d.ContainsKey(w) ? d[w] + 1 : 1); return d; })
)
.ToList();
This version iterates over each element in your source array exactly once. The output is in the same format as the first version.
var result = strings.Select((s, i) => new { s, i })
.GroupBy(x => x.i / 500)
.Select(x => x.GroupBy(y => y.s)
.Select(z => new {
Name=z.Key,
Count=z.Count()
}).ToList())
.ToList();
Try
var grouping = Enumerable.Range(0,2000)
.Select(i => i / 500)
.Zip(Strings, (i,s) => new { Group = i, Str = s})
.GroupBy(anon => anon.Group,
anon => anon.Str,
(key,g) => new
{
Key = key,
Art = g.Count(str => str == "art"),
Economy = g.Count(str => str == "economy"),
Politic = g.Count(str => str == "politic"),
Sport= g.Count(str => str == "sport")
});
foreach(anon in grouping)
{
//textbox logic OP will have to change to suit
TextBox1.WriteLine(String.Format("Group: {0}", anon.Key));
TextBox1.WriteLine(String.Format("Art: {0}",anon.Art));
TextBox1.WriteLine(String.Format("Economy: {0}",anon.Economy ));
TextBox1.WriteLine(String.Format("Politic: {0}",anon.Politic ));
TextBox1.WriteLine(String.Format("Sport: {0}",anon.Sport));
}
Alternatively (as per Snowbear)
var grouping = Strings.Select((s,i) => new { Group = i / 500, Str = s})
.GroupBy(anon => anon.Group,
anon => anon.Str,
(key,g) => new
{
Key = key,
Art = g.Count(str => str == "art"),
Economy = g.Count(str => str == "economy"),
Politic = g.Count(str => str == "politic"),
Sport= g.Count(str => str == "sport")
});
foreach(anon in grouping)
{
//textbox logic OP will have to change to suit
TextBox1.WriteLine(String.Format("Group: {0}",anon.Key + 1));
TextBox1.WriteLine(String.Format("Art: {0}",anon.Art));
TextBox1.WriteLine(String.Format("Economy: {0}",anon.Economy ));
TextBox1.WriteLine(String.Format("Politic: {0}",anon.Politic ));
TextBox1.WriteLine(String.Format("Sport: {0}",anon.Sport));
}
int CountElementsInGroup = 500;
//from 500 to 1000
int NumberGroup = 2;
string[] GroupTypes = new string[4] { "art", "economy", "sport", "politic" };
//Fill example array
string[] arr = new string[2000];
Random rand = new Random();
for (int i = 0; i < arr.Length;i++ )
arr[i] = GroupTypes[rand.Next(0, 3)];
var res = (from p in arr.Skip((NumberGroup - 1) * CountElementsInGroup).Take(CountElementsInGroup)
group p by p into g
select new GroupCountClass { GroupName = g.Key, GroupCount = g.Count() });
textBox1.Text = "";
foreach (GroupCountClass c in res)
{
textBox1.Text += String.Format("GroupName:{0} Count:{1};",c.GroupName,c.GroupCount);
}

Categories

Resources