Pass a array value to another array - c#

I have a Array.It has for example 10 rows.
I need to checka flg. if flag has value false it goes to array number one,if it have flag true it goes go array number 2.I'm trying something like this.
if (lista2[i].FLG_FALHA == true)
{
listaInc[c] = lista2[i];
i++;
c++;
}
else
{
listaAlr[o] = lista2[i];
o++;
i++;
}
This is where i declare the arrays.
List<AcompanhamentoSiltIncDTO> lista2 = new List<AcompanhamentoSiltIncDTO>();
List<AcompanhamentoSiltIncDTO> listaInc = new List<AcompanhamentoSiltIncDTO>();
List<AcompanhamentoSiltIncDTO> listaAlr = new List<AcompanhamentoSiltIncDTO>();
I get this error,it's like the arrays are not initialized.
"{"The index was out of range, it should be non-negative and less than the size of the collection. \ R \ nName parameter: index"}"

You should call the Add() method of your list:
if (lista2[i].FLG_FALHA == true)
listaInc.Add(lista2[i]);
else
listaAlr.Add(lista2[i]);
Otherwise, since your listaAlr and listaInc have no element, you get cannot access element at position o : listaInc[o]

You get this error because you got out of range of your array. Check out your indexes. But for this task I suggest you working with linq. It gives you a lot of good functionality.
And if you have "List<>" you need to add elements to this list with "Add" method.
So code will be the next:
if (lista2[i].FLG_FALHA == true)
{
listaInc.Add(lista2[i]);
i++;
}
else
{
listaAlr.Add(lista2[i]);
i++;
}
But as I said you may use LinQ.
Code will be the next:
listInc = lista2.Where(x => x.FLG_FALHA);
listAlr = lista2.Where(x => !x.FLG_FALHA);

You can solve this with LINQ.
var listaInc = from n in lista2
where n == true
select n;
var listaAlr = from n in lista2
where n == false
select n;
Bits more, bits less, but that is what I would do.

Related

Problem finding indexes of items in a list

I'm trying to find indexes of items in a list.
For example number 0 in a list of numbers.
With this code I have found index of zeros only when there one zero in the list.
When zeros are two or more, the second index doesn't get correct.
Isn't method IndexOf() the correct one to use?
How can I find all the indexes of an item, not only the first?
Thanks
var zerosInList = list.FindAll(x => x == 0);
if (zerosInList.Count > 0)
{
foreach (var item in zerosInList) //finding indexes of zeros
{
indexes.Add(list.IndexOf(item));
Console.Write("found zero in position: "); PrintList(indexes);
}
The List<T>.IndexOf compares elements using the default equality comparer of T. For integers, it uses value equality. All zeros in your zerosInList collection are considered to be the same. In other words, the "second zero" or "third zero" in your foreach loop is considered no different than the "first zero", therefore the IndexOf method always returns the index of the first 0 it encounters, not the particular zero that's the subject of the foreach loop's current iteration.
You can make a collection of all the zero's indexes in your original list this way:
var indexesOfZeros = new List<int>();
for (int i = 0; i < list.Count; i++)
{
if (list[i] == 0)
{
indexesOfZeros.Add(i);
}
}
IndexOf method in C# searches one string for another. It returns the index of the string part, if one is found.
But you can try this:
for(int i=0;i<yourFirstList.Count;i++)
//yourFirstList is the list with all the numbers
{
if(yourFirstList.ElementAt(i).value==0){
indexes.Add(i);
}
}
Console.Write("found zero in position: "); PrintList(indexes);
You could also use the following Linq expression :
List<int> zeroList = intList.Select((val,idx) => new {val,idx})
.Where(t => t.val == 0)
.Select(pp => pp.idx).ToList();
the first creates an anonymous type containing the original value & offset, the where clause filters out all instances where the value is 0 & the final select returns the index in the original list.
I like Lambdas :D
List<int> indexes = list.Select((item, index) =>
item == 0 ? index : -1
).Where(i => i != -1).ToList();
Console.Write("found zero in position: "); PrintList(indexes);
List.FindAll method returns items that match your requisite, not their index. I mean if you have lets say
list[0] = 0;
list[1] = 4;
list[2] = 0;
and apply FindAll( x => x == 0); to list, you get a list which contains 2 zero values, and I think you expect indexes to contain 0 and 2 in this case. You could use .IndexOf() to accomplish your task, iterating through your items until you get a -1:
int indexOfItem = 0;
while(indexOfItem != -1 && indexOfItem < list.Count) {
indexOfItem = list.IndexOf(0, indexOfItem);
if (indexOfItem != -1) {
indexes.Add(indexOfItem);
indexOfItem++;
}
}

Apply last non empty string to empty string?

A file is read in. Looks for lines that have a number that beings with an S The lines that do not have an S are maintained. Saves to an array. I am then populating an existing gridview with the same amount of lines.
As a place holder I have set the blank lines to *** This is where I'm stuck. I need the empty strings to be populated with the last non empty string.
So for example if the readout is:
1
2
3
Empty
Empty
Empty
4
Empty
6
I'd want it displayed as:
1
2
3
3
3
3
4
4
6
I can't figure out how to do that. I've been searching all day for examples but can only find ways of grabbing either the first or last number of my array is all. Here is my code.
var sLines = File.ReadAllLines(cboPartProgram.Text)
.Where(s => !s.StartsWith("'"))
.Select(s => new
{
SValue = Regex.Match(s, "(?<=S)[\\d.]*").Value,
})
.ToArray();
string LastSValue = "";
string Value = "";
for (int i = 0; i < sLines.Count(); i++)
{
if (sLines[i].SValue == "")
{
LastSValue = "***";
Value = LastSValue;
}
else
{
Value = (sLines[i].SValue);
}
}
Ok I think I got it.
for (int i = 0; i < sLines.Length; i++)
{
if (sLines[i].SValue == "" && i > 0)
{
foreach (var empt in sLines[i].SValue)
{
LastSValue = sLines[i - 1].SValue;
Value = LastSValue;
}
}
else
{
Value = (sLines[i].SValue);
}
On a side note, when I copy my code I use the code option above to format it, but I notice someone always has to correct my spacing. Its copied straight from the IDE but there are always spaced each line that I guess shouldn't be. Is there a different way I should do it?
UPDATE
If I should ask this as a new question let me know, but it's so dependent on this that I thought I should keep it here.
Using the code I posted above that does what I needed it too. I've been trying to edit this so that if there is NO previous number, so for example if there if line 1 has no number but the rest do, then just apply the string "NA" otherwise still do what the code above does to the rest of the lines.
I guess maybe the best way would be to just take the results from the above code, and if there are any empty spaces left, apply "NA" but I can't figure it out.
In your example, you just need to take the value of the row before to fill the current value. Something like the following :
for (int i = 0; i < sLines.Length; i++)
{
if (sLines[i].SValue == "" && i > 0)
{
sLines[i].SValue = sLines[i-1].SValue;
}
else
{
sLines[i].SValue = sLines[i].SValue;
}
}
Your example has one more issue but currently I'll focus only on gathering the "last non empty" string.
If you look at your example you can spot few things that could potentially help you finding solution. These are for loop and reference to original list that stays intact.
For my example I'll use Linq because it will be much easier.
First of all I'll copy all from before for loop ( if that makes sense :D ) :
var sLines = File.ReadAllLines(cboPartProgram.Text)
.Where(s => !s.StartsWith("'"))
.Select(s => new
{
SValue = Regex.Match(s, "(?<=S)[\\d.]*").Value,
})
.ToArray();
string LastSValue = "";
string Value = "";
Just because it's okay and will work for now.
With your for loop I'll make modifications :
for (int i = 0; i < sLines.Count(); i++)
{
// `i` is representing current "index" of processed "word"
// we can use this to find last "valid" element
// string notEmpty = sLines.Take(i).LastOrDefault(word => !string.IsNullOrEmpty(word));
// but since you want to assign this to `Value` and there can be not empty string at `i` index
// we can make it in one line :
Value = string.IsNullOrEmpty(sLines[i]) ? sLines.Take(i).LastOrDefault(word => !string.IsNullOrEmpty(word)) : sLines[i].SValue;
// instead of your previous logic :
//if (sLines[i].SValue == "")
//{
// LastSValue = "***";
// Value = LastSValue;
//}
//else
//{
// Value = (sLines[i].SValue);
//}
}
Another problem which I think you'll face is that first value ( judging by the input ) can also be empty. Which will throw exception in my example. This will also be impossible to fit this kind of solution because there's no previous value ( at all ).
From what I understand, if you want to store the result in Value and do something else with it inside the loop (instead of changing it in the array), what you probably want is this:
for (int i = 0; i < sLines.Count(); i++)
{
if (sLines[i].SValue == "")
{
Value = LastSValue;
}
else
{
Value = (sLines[i].SValue);
LastSValue = Value;
}
// use Value
}
I would also suggest using sLines.Length instead of Count(), which is made for sequences where the length isn't known in advance - it's supposed to literally count the elements one by one. In this case it would probably be optimized but if you know you're dealing with an array, it's a good idea to ask for the length directly.
EDIT:
To get "NA" if there's no previous number, just initialize LastSValue to this value before the loop:
string LastSValue = "NA";
That way, if Value is empty and there was not LastSValue set before, it will still be "NA".
EDIT2:
A solution similar to the one from #Cubi, to change it in place:
for (int i = 0; i < sLines.Length; i++)
{
if (sLines[i].SValue == "")
sLines[i].SValue = i > 0 ? sLines[i-1].SValue : "NA";
}

Splitting List based on element variable and element position

hey I'm trying to split a list based on if a bool of the element is true or not. but each time it has passed some true's and encounters a false i want it also to start a new list with the all the false until it encounters true again and so on. so basicly grouping sequences of falses and trues
public void SortWalls()
{
List<Node> innerWallNodes;
foreach(Wall w in walls)
{
WallAxis ax = w.axis;
innerWallNodes = new List<Node>();
for(int i=w.wallNodes.Count-1; i>=0; i--)
{
if(w.wallNodes[i].markedForDoor)
{
//split wall!!
innerWallNodes.Add(w.wallNodes[i]);
w.wallNodes.RemoveAt(i);
}
}
if(innerWallNodes.Count > 0)
{
Wall wall = new Wall(innerWallNodes, ax);
innerWalls.Add(wall);
}
}
}
i did it like this and then build a mesh based on the first and last element of a List. but since there are many scenarios where the innerWallNodes could be somewhere in the middle of the list that get "cut out" and so my remaining "outer wall" would still have the same node index in my grid for the first and last in it's list, still overdrawing my "inner wall"
so lets say every node !markedForDoor is 0 and a every node markedForDoor is 1 and they order something like below in my list.
like this:
|000|11111|00000|11|000| how would i get a list for every between |...| ?
how do i do this in a simple way. I thought Linq would have something for this but can't find anything.
Linq won't help. Here is the code:
List<List<YouObjectType>> SplitList(List<YourObjectType> listToSplit) {
List<List<YouObjectType>> listOfLists = new List<List<YourObjectType>>();
List<YourObjectType> tmp = new List<YourObjectType>();
foreach(YourObjectType item in listToSplit) {
if (tmp.Count > 0
&& tmp[tmp.Count - 1] != item) {
// Compare you items here as you wish,
// I'm not sure what kind of objects
// and what kind of comparison you are going to use
listOfLists.Add(tmp);
tmp = new List<YourObjectType>();
}
tmp.Add(item);
}
if (tmp.Count > 0) {
listOfLists.Add(tmp);
}
return listOfLists;
}
Here is a simple way of doing that (no Linq)
List<Node> input = ...;
var output = new List<List<Node>>();
for (int end = 0; end < input.Count; )
{
int start = end;
while (++end < input.Count && input[end].markedForDoor == input[start].markedForDoor) { }
output.Add(input.GetRange(start, end - start));
}
Lookup Group Results by Contiguous keys on MSDN.
See how it applies to your case on Rextester.

Selecting indexes from Multidimensional Array where the value is 0 is not working

Please i am given a task to return an indexes from a 2d array that is frequently updating. Actually is an assignment on the 2048 game . When ever, a random numb is added, i want it added randomly to the free/empty tiles as it should be. Thats where the array value is 0 in my case.
private static int[][] addTile()
{
rd = new Random();
int px, py;
px = rd.Next(0, 4);
py = rd.Next(0, 4);
List<int> availableInd = randPosition(py);
int r = rd.Next(0, availableInd.Count);
int newPx = availableInd[0];
if (Tiles[py][newPx] == 0)
{
Tiles[py][newPx] = rd.Next(0, 20) == 0 ? rd.Next(0, 15) == 0 ? 8 : 4 : 2;
}
else
{
py = py; // I put a break here
}
}
My randPosition() method loks like the fflg;
public static List<int> randPosition(int num)
{
List<int> indexes = new List<int>();
// var emptyTiles = arr.Where(x => x == 0).ToList();
indexes = Tiles[num].Select((s, index) => new { s, index })
.Where(x => x.s == 0)
.Select(x => x.index)
.ToList();
if (indexes.Count > 0)
return indexes;
//Incase The above fails. I would seach row by row
//for an empty tile
for (int c = 0; c < Tiles.Count(); c++)
{
indexes = Tiles[c].Select((s, index) => new { s, index })
.Where(x => x.s == 0)
.Select(x => x.index)
.ToList();
if (indexes.Count > 0)
break;
}
return indexes;
}
First i ramdomly generate my y-axis , i then pass it to the randPosition to check if there exist an empty cell in the said axis. If there are , get the indexes of the cells. IF there are not, i then perform an advance row by row search below to make sure only empty tiles are returned. However, when i put the break at the else of the first method, i realized still occupied tiles/cells are return as empty. I tried alot of manipulations yet to no avail. please where do i go wrong ? How do i best handle this ? Any help suggestion or alternative would highly be appreciated. Thank you
This is somewhat of a guess, but I think you have a logic error:
randPosition(num) is supposed to return the "empty" cells in row num. If it does not find any, it searches row-by-row until it does find an empty cell.
The problem is, the caller doesn't know if the original search failed. It's entirely possible that the indices returned represent cells of a completely different row than was asked for. That may be why you see "occupied" cells returned as "empty".
Here's an analogy:
You're taking a trip to New York. You go to the airport to book a flight (I know, no one does this anymore). You ask for all empty seats on row 7 (because you like row 7). The Customer Service Agent looks up row 7 and finds that there are no empty seats. Instead of telling you that, she instead start looking through all other rows and finds an empty seat (C) on row 15. So she tells you that "Seat C is empty". The problem is, you think she's talking about row 7! You have no indication that row 7 was full or which row she's referring to.
Either the caller needs to iterate through other rows (so that it knows which row the empty cells are on), or the method needs to have some sort of feedback that indicates which row the empty cells are on.

Transform sequence in Linq while being aware of each Select/SelectMany result

Here's my problem. I have one specific list, which I'll present as a int[] for simplicity's sake.
int[] a = {1,2,3,4,5};
Suppose I need to transform each item on this list, but depending on the situation, I may return an int or an array of ints.
As an example, suppose I need to return {v} if the value is odd, and {v,v+1} if the value is even. I've done this:
int[] b = a.SelectMany(v => v % 2 == 0 ? new int[] { v, v+1 } : new int[] { v })
.ToArray();
So if I run this, I'll get the expected response:
{1,2,3,3,4,5,5}
See that I have repeating numbers, right? 3 and 5. I don't want those repeating numbers. Now, you may tell me that I can just call .Distinct() after processing the array.
This is the problem. The SelectMany clause is fairly complex (I just made up a simpler example), and I definitely don't want to process 3 if it's already present in the list.
I could check if 3 is present in the original list. But if I got 3 in the SelectMany clause, I don't want to get it again. For instance, if I had this list:
int[] a = {1,2,3,4,5,2};
I would get this:
{1,2,3,3,4,5,5,2,3}
Thus returning v (my original value) and v+1 again at the end. Just so you can understand it better v+1 represents some processing I want to avoid.
Summarizing, this is what I want:
I have a list of objects. (Check)
I need to filter them, and depending on the result, I may need to return more than one object. (Check, used SelectMany)
I need them to be distinct, but I can't do that at the end of the process. I should be able to return just {v} if {v+1} already exists. (Clueless...)
One thing I thought about is writing a custom SelectMany which may suit my needs, but I want to be sure there's no built-in way to do this.
EDIT: I believe I may have mislead you guys with my example. I know how to figure out if v+1 is in a list. To be clear, I have one object which has 2 int properties, Id and IdParent. I need to "yield return" all the objects and their parents. But I just have the ParentId, which comes from the objects themselves. I'm able to know if v+1 is in the list because I can check if any object there has the same Id as the ParentId I'm checking.
ANSWER: I ended up using Aggregate, which can be used to do exactly what I'm looking for.
Does this simple loop with the HashSet<int> help?
int[] a = {1,2,3,4,5,2};
var aLookupList = new HashSet<int>();
foreach (int i in a)
{
bool isEven = i % 2 == 0;
if (isEven)
{
aLookupList.Add(i);
aLookupList.Add(i + 1);
}
else
{
aLookupList.Add(i);
}
}
var result = aLookupList.ToArray();
What about this using Aggregate method. You won't be processing numbers that are already in the list, wheather they were in the original list or as a result of applying (v + 1)
int[] v = { 1, 2, 3, 4, 5, 2 };
var result = v.Aggregate(new List<int>(),
(acc, next) =>
{
if (!acc.Contains(next))
return (next % 2 == 0) ? acc.Concat(new int[] { next, next + 1 }).ToList()
: acc.Concat(new int[] { next }).ToList();
else
return acc;
}).ToArray();
var existing = new HashSet<int>(a);
var result = existing
.Where(v => v % 2 == 0 && !existing.Contains(v + 1))
.Select(v => v + 1)
.Concat(existing)
.ToArray();
As I understand you have this input:
int[] a = {1,2,3,4,5};
And the output should also be {1,2,3,4,5} because you don't want duplicated numbers as you describe.
Because you use an array as input, you can try this code:
var output = a.SelectMany((x,i)=> x % 2 == 0 ? new []{x,x+1} :
i > 0 && a[i-1]==x-1 ? new int[]{} : new []{x});
//if the input is {1,2,4,5}
//The output is also {1,2,3,4,5}

Categories

Resources