I'm trying to get a distinct list to my view.I need to select records from a list randomly and put it in to another list.The following code works..But it contain duplication records..How can I overcome this problem?
Note: the variable "budget" is a parameter passed in to the controller and "model1" is a List of PlanObjectsViewModel
int count = 0;
foreach (var item in model1) { count++; }
List<PlanObjectsViewModel> result = new List<PlanObjectsViewModel>();
Random rand = new Random();
double? temp=0;
while(budget>temp)
{
int randi = rand.Next(0, count);
var nthItem = model1.OrderBy(p => p.Id).Skip(randi).First();
temp += nthItem.Price;
if (!result.Contains(nthItem)) // Think this is the wrong point
{
result.Add(nthItem);
}
}
Use a HashSet<PlanObjectsViewModel>
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
// Input array that contains three duplicate strings.
string[] array1 = { "cat", "dog", "cat", "leopard", "tiger", "cat" };
// Display the array.
Console.WriteLine(string.Join(",", array1));
// Use HashSet constructor to ensure unique strings.
var hash = new HashSet<string>(array1);
// Convert to array of strings again.
string[] array2 = hash.ToArray();
// Display the resulting array.
Console.WriteLine(string.Join(",", array2));
}
}
Output:
cat,dog,cat,leopard,tiger,cat
cat,dog,leopard,tiger
there are two ways to do this, use a hashset instead of list for your result, or use Distinct()
HashSet<PlanObjectsViewModel> result
or
return result.Distinct();
You will have have to implement the Equals() method for this to work with objects, a which point your current code should work too.
Actually you have made it the correct way. For me it looks like you didnt implemented Equals and GetHashCode which are used by List.Contains to compare objects. Well basically GetHashCode is not mandatory but its a good design if you implemented the one to implement the other one.
But ofcourse you can use HashSet as pointed in the other answeres.
Related
I'm making a program that counts how many lines of code are in a folder where you input the extension you want to check for (like .cs) and it lists all of the files with that extension and their lines of code like this:
1. BackgroundProcesses.cs: 153
2. App.xaml.cs: 15
3. MainTableManifest.cs: 41
At the moment, I'm just using Directory.GetFiles() to get the files and they're not in any particular order. However, I want to sort each file by how many lines it has to display it from smallest to largest for easy viewing of what the largest files are with an output like this:
1. App.xaml.cs: 15
2. MainTableManifest.cs: 41
3. BackgroundProcesses.cs: 153
Here's what my two-dimensional jagged array basically looks like:
string[][] arr = new string[][] {
new string[]{"file1", "324"},
new string[]{"file2", "1903"},
new string[]{"file3", "617"}
};
Obviously, I would need to convert the strings to numbers when sorting (I don't think you can have a jagged array with different array types). Any ideas on how to do this to convert that jagged array to something like this?
string[][] arr = new string[][] {
new string[]{"file1", "324"},
new string[]{"file2", "617"},
new string[]{"file3", "1903"}
};
You should use ValueTuple instead of Jagged Arrays.
(string Filename, int Lines)[] files = ...
After that you can use Linq for sorting
var sorted = files
.OrderBy(item => item.Lines)
.ThenBy(item => item.Filename);
One of the major points of an object oriented programming language such as C# is to allow you to define custom objects and have behaviours related to them rather than complex structures of native types.
Have you tried creating a custom object to represent this data that can then be sorted accordingly?
e.g.
public class FileRecord
{
public string FileName { get; }
public int NumberOfLines { get; }
public FileRecord(string fileName, int numberOfLines)
{
this.FileName = fileName;
this.NumberOfLines = numberOfLines;
}
}
Then you can either make this class implement IComparable or define a custom comparer for the sort. My preference would be for using a custom comparer because you may want to sort using different criteria and the same class elsewhere.
This would look like:
public class FileRecordComparer : IComparer<FileRecord>
{
public int Compare(FileRecord x, FileRecord y)
{
// Could handle nulls here if you're expecting nulls
int lineCompare = x.NumberOfLines.CompareTo(y.NumberOfLines);
if (lineCompare == 0)
return x.FileName.CompareTo(y.FileName);
else
return lineCompare;
}
}
Then you can have the following code to sort your array (you'll have to populate it in the way you are currently of course)
// Could use a list here if you don't know the number of files
FileRecord[] records = new FileRecord[numberOfFiles];
// ...
// Populate the records as you do currently, but creating instances of FileRecord
// ...
Array.Sort(records, new FileRecordComparer());
Try
var files = arr.OrderBy(x =>Convert.ToInt64(x[1]));
you could use Tuple with Linq to simplify your problem get the files and number of lines in same time:
(string Filename, int numberLines)[] files = Directory.GetFiles(#"d:\", "*.cs")
.Select(f => (f, File.ReadLines(f).Count()))
.OrderBy(f => f.Item2).ToArray();
foreach (var file in files)
{
Console.WriteLine($"file:{file.Filename} lines:{file.numberLines}");
}
if you have lot of files in your directory, i suggest you to use EnumerateFiles instead of GetFiles.
I have a c# class that looks like this:
public class MemberData
{
public int meme_ck;
public string meme_name;
public bool meme_active;
public MemberData(int ck2, string name2, bool active2)
{
meme_ck = ck2;
meme_name = name2;
meme_active = active2;
}
}
I have made two arrays out of that class:
private MemberData[] memarray1 = new MemberData[10000];
private MemberData[] memarray2 = new Memberdata[10000];
Over the course of my application I do a bunch of stuff with these two arrays and values change, etc. Member's name or active status may change which results in the ararys becoming different.
Eventually I need to compare them in order to do things to the other one based on what results are kicked out in the first one.
For example, member is de-activated in the first array based on something application does, I need to update array 2 to de-activate that same member.
I am trying to use some database design philosphy with the int CK (contrived-key) to be able to rapidly look up the entry in the other array based on the CK.
Since I can't figure it out I've had to resort to using nested for loops like this, which sucks:
foreach (Memberdata md in memarray1)
{
foreach (Memberdatamd2 in memarray2)
{
if (md.ck = md2.ck)
{
//de-activate member
}
}
}
Is there a better way to do this? I just want to find the index in the second array based on CK when I have the CK value from the first array.
Any other tips or advice you have about structure would be appreciated as well. Should I be using something other than arrays? How would I accomplish this same thing with Lists?
Thanks!
Should I be using something other than arrays?
Yes. Don't use arrays; they are seldom the right data structure to use.
How would I accomplish this same thing with Lists?
Lists are only marginally better. They don't support an efficient lookup-by-key operation which is what you need.
It sounds like what you want is instead of two arrays, two Dictionary<int, MemberData> where the key is the ck.
I totally agree with Eric Lippert's answer above. It is better you do not use Array.
Same thing can be achieved using List<MemberData>. You can use LINQ as well to query your DataStructure.
Following is one of the way just to achieve your result using array
class Program
{
static MemberData[] memarray1 = new MemberData[10000];
static MemberData[] memarray2 = new MemberData[10000];
static void Main(string[] args)
{
for (int i = 0; i < memarray1.Length; i++)
{
memarray1[i] = new MemberData(i + 1, "MemName" + i + 1, true);
memarray2[i] = new MemberData(i + 1, "MemName" + i + 1, true);
}
// SIMULATING YOUR APP OPERATION OF CHANGING A RANDOM ARRAY VALUE IN memarray1
int tempIndex = new Random().Next(0, 9999);
memarray1[tempIndex].meme_name = "ChangedName";
memarray1[tempIndex].meme_active = false;
//FOR YOUR UDERSTADNING TAKING meme_ck IN AN INTEGER VARIABLE
int ck_in_mem1 = memarray1[tempIndex].meme_ck;
//FINDING ITEM IN ARRAY2
MemberData tempData = memarray2.Where(val => val.meme_ck == ck_in_mem1).FirstOrDefault();
// THIS IS YOUR ITEM.
Console.ReadLine();
}
}
Pre-information
-User inputs data in console
-Save data in an Array of 2 elements[2]
-Save the Array with 2 elements in a LIST
*Now what i try to achieve is that the user can check if search is in the list regardless if its written in lower or upper case.
List<string[]>MyList = new List<string[]>();
var[] myArray = new [] { "A", "B" };
MyList.Add(myArray);
int y = 0;
Console.WriteLine("Inpu what you are Searching For: ");
string serchString = Console.ReadLine();
serchString = serchString.ToLower();
for (int i = 0; i < MyList.Count; i++)
{
List<object> oneTimeList = new List<object>();
oneTimeList.AddRange(myList[i]);
Console.WriteLine(oneTimeList);
if (MyList[i].Contains(serchString.ToLower()))
{
Console.WriteLine("Yes you have added this");
}
else if (!myList[i].Contains(serchString))
{
y += 1;
}
}
if (y == myList.Count)
{
Console.WriteLine("You Have not entered this Yet");
}
My logic(maybe not the best in the planet :P) says that i have to make a comparison of all the elements of the array in turn with the search the user made and if its true continue, And in order to make this i need first to get the information of the arrays of the list and convert them to a list and then convert them to lowercase.
Every thing goes fine until the part where i try to add the Arrays to the List and all i am adding are Arrays[].
Any Suggestion on how to approach this issue or how to pass the elements of an ARRAY that is inside of a LIST to a NEW LIST?
It sounds like to want to take an array of strings (assumed as you mention lower casing it), add them all to a list, lower-case them and then compare?
This being the case you don't need to do any of that. You can simply do:
var myArray = new [] { "A", "B", "C" }
var toCheck = "a";
//Use the IEnumerable<T>.Contains() Linq extension
if (myArray.Contains(toCheck, StringComparer.OrdinalIgnoreCase))
{
//...
}
If you really want to add them to a list I can't give you an example using your code, but to "pass elements of an array to a new list" you can do any of the following:
//List<T>(IEnumerable<string>) constructor
var newList = new List<string>(myListOfStrings);
//List<T>.AddRange(IEnumerable<string>)
var newList = new List<string>();
newList.AddRange(myListOfStrings);
//List<T>.Add(T) (adding items one at a time)
var newList = new List<string>();
newList.Add(myListOfStrings[index]);
It's worth noting here as well that any of the above references to myListOfStrings could be an array of strings (string[]) or a list of strings (List<string>) because they both implement IEnumerable<string> which is the type the above methods require (except for Add which wants a single item).
Here is the documentation for List that describes in details how to use each of the above (and all other other available methods...)
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
how to inset a new array to my jagged array
i have a problem, where i dont know how i can make a string array variable in array length.
i have this code now below:
string[] p = new string[10];
int num = 0;
foreach (Product products in GetAllProducts())
{
//do something
p[num]= "some variable result"
num++
}
The problem is, that i dont know how many of "p" i will get, although i know it atleast will be less than 10.
but if i put it on 0, i will get an error when i start it, because it doesn't know the "p[num]"
So i am looking for some way to make "p" have a variable length.
anyone could help me out a bit? thanx
============Solved==========
List<string> p = new List<string>();
int num = 0;
foreach (Product products in GetAllProducts())
{
string s= null;
//do something ( create s out of multiple parts += s etc.)
p.add(s)
num++
}
thanx to solution poster
Use an List<string> instead of an array, if you do not know the number of items you will need to add.
Your array length cannot be modified after it has been instantiated. Use ArrayList or Generic Lists.
var p = new new List<string>(10);
foreach (Product products in GetAllProducts())
{
//do something
p.Add("some variable result");
}
What does GetAllProducts() return? Does it have a count or a length?! You should call that first, save it in a variable, get the count/length and then declare your array!
There's two solution.
If you want to keep using array :
int num = 0;
var list = GetAllProducts();
string[] p = new string[list.Length]; // Or list.Count if this is a collection
foreach (Product products in list)
{
//do something
p[num] = "some variable result";
num++;
}
Otherwise you should use a List like this :
List<string> p = new List<string>();
foreach (Product products in GetAllProducts())
{
//do something
p.Add("some variable result");
}
Use Array.Resize() method, which allows to resize it (by n number of indexes).
In my exmaple I will reize by 1 on each step of the way:
string[] array = new string[3]; //create array
for (int i = 0; i < 5; i++)
{
if (array.Length-1 < i) //checking for the available length
{
Array.Resize(ref array, array.Length + 1); //when to small, create a new index
}
array[i] = i.ToString(); //add an item to array[index] - of i
}
Because your code is using a foreach on the result from GetAllProducts, then GetAllProducts must be returning a IEnumerable collection. Probably the best solution would be to simply assign the result of GetAllProducts to such a collection. For example, perhaps it already returns a list of strings? So you can do:
List<string> strings = GetAllProducts();
There is no need to have a foreach loop to create an array when you already have a collection anyway being returned from GetAllProducts.
Or simply:
var strings = GetAllProducts();
to let the compiler work out the type of strings.
Most things you can do with an array you can also do with a List, and some more (such as adding items to the end of the List).
Perhaps you can post the signature of GetAllProducts (especially its return type) so we can better advise you?
I see many gave you the right answer which is the use of Lists. If you still need an array in the end, you can easily convert your list into an Array like this :
string[] tempArray = myList.ToArray();
Let's say a program like this:
class MyClass
{
public int Numbers;
public char Letters;
}
class Program
{
static void Main()
{
var mc = new MyClass[5];
for (var i = 0; i < 5; i++)
{
mc[i].Numbers = i + 1;
mc[i].Letters = (char) (i + 65);
}
}
}
Now, let's suppose an 'X' method that requires ALL the numbers contained in the object mc, in a separate array, that's sent as a parameter.
My first idea is a for, a new integers array, and copy one by one onto its respective position. But, what if the MyClass gets different, now it has strings and floats, and I wanna pull out the strings, now the for has to be completely redefined in its inside part to create the needed array for another 'X' method.
I know of cases where Linq helps a lot, for example, generics for Sum, Average, Count and another numeric functions, and of course, it's combination with lambda expressions.
I'm wondering if something similar exists to make the above arrays of MyClass (and anothers of course) in a faster-generic way?
If you want to use LINQ, you can do something like the following:
int [] numbers = mc.Select<MyClass, int>(m => mc.Number).ToArray();
To make it more generic than that, it gets a bit more complicated, and you may need reflection, or dynamic objects. A simple example with reflection would be:
private TValue[] ExtractFields<TClass, TValue>(TClass[] classObjs, string fieldName)
{
FieldInfo fInfo = typeof(TClass).GetField(fieldName, BindingFlags.Public | BindingFlags.Instance);
if (fInfo != null && fInfo.FieldType.Equals(typeof(TValue)))
return classObjs.Select<TClass, TValue>(c => (TValue)fInfo.GetValue(c)).ToArray();
else
throw new NotSupportedException("Unidentified field, or different field type");
}
And then just call it like:
int [] fields = ExtractField<MyClass, int>(mc, "Number");
If you are using C# 4.0, then you may use dynamic
class MyClass
{
public dynamic Numbers;
public char Letters;
}
EDIT: based on comments
I am not sure if this is what you want:
int[] arr = mc.Select(a => a.Numbers).ToArray<int>();
or without casting
int[] arr = mc.Select(a => a.Numbers).ToArray();
Why not just use Dictionary<int, char>, or if the data type is unknown then simply Dictionary<object, object>
If your goal is to generate a new array which is detached from the original array, but contains data copied from it, the most generic thing you could do would be to define a method like:
T my_array[]; // The array which holds the real things
U[] CopyAsConvertedArray<U>(Func<T,U> ConversionMethod);
That would allow one to generate a new array which extracts items from the original using any desired method.