I think the answer to this is pretty obvious, but it's friday so my brain isn't functioning entirely.
I'm working in an asp.net mvc application where I get the id of a selected row. Every time I click a row the id of that row is send to my controller.
What I want to do is output the id just as regular plain text.
This isn't too hard, I use this code:
public string GetInformation(int id)
{
return id.toString();
}
But the user can select multiple rows at once, what happens now is that the id just changes from the first selected row to the second one.
What I want is both the id's to be returned, separated by a comma.
This is what I tried:
public string[] GetInformation(int id)
{
List<string> oud = new List<string>();
oud.Add(id.ToString());
return oud.ToArray();
}
But then it just shows System.String[] as output.
Ok, I'm going to prefix this by saying that I think using sessions for state is generally a bad idea. However, it's an easy way to show state management and retaining the list between requests.
Update your function to this:
public string[] GetInformation(int id)
{
var list = Session["oud"] as List<string>;
if (list == null)
{
list = new List<string>();
Session["oud"] = list;
}
list.Add(id.ToString());
return list.ToArray();
}
Each time you call this method it will get the list from session (user state management). If the list returned from session is null (it's not actually there) we create a new list of strings and add it to the session.
To test this I put the following in an index action of an MVC controller before return View(). When I refresh the page I can see the random id being appended to the list. The same will apply if you make a call from the client.
Random r = new Random();
GetInformation(r.Next(1, 10));
Hope this helps!
Update
Iterating over an array in razor view and printing each item
In your razor view, if you have added this array to your model as MyIds, you could use the following:
#foreach (var id in Model.MyIds)
{
<p>#Html.Raw(id)</p>
}
Update 2
I'm going to make this very easy for you:
public string GetInformation(int id)
{
var list = Session["oud"] as List<string>;
if (list == null)
{
list = new List<string>();
Session["oud"] = list;
}
list.Add(id.ToString());
return string.Join(", ", list);
}
The function now returns a comma separated list of ids that you have passed through.
But then it just shows System.String[] as output.
Well, you're not showing us how you actually output anything. But presumably you're getting a value:
var output = GetInformation(input);
and then trying to write output directly as a string. However, string[] is an array and doesn't have a default string representation. All objects in .NET which don't have a .ToString() implementation inherit their implementation from System.Object, which defaults to outputting the type name.
Instead of outputting the object itself, which is semantically something like this:
Write(output)
(again, semantically, since we don't know how you're actually outputting it, so consider this pseudo-code)
Loop over it for your output:
foreach (var value in output)
Write(value)
You'll have to handle formatting (new lines, delimiters, etc.) for however you want to display the values as a UI concern. But the point, basically, is that you need to loop over your values and output them individually rather than as one big array.
There are shortcuts which will loop over it for you, if you'd like. For example:
Write(string.Join(",", output))
That would "join" all of the strings in output for you, using "," as a delimiter.
Edit: Another problem that you seem to be experiencing is that your method only ever returns a new list of exactly one object:
public string[] GetInformation(int id)
{
List<string> oud = new List<string>();
oud.Add(id.ToString());
return oud.ToArray();
}
This method shouldn't really have the responsibility of maintaining the list. This is because the method itself is stateless, all it really does is convert an integer value to a string. (Which you don't really need a method for, but whatever.) Consuming code should maintain state.
So keep the method as-is:
public string GetInformation(int id)
{
return id.toString();
}
And have the consuming code maintain the collection of values. Something like this:
var output = GetInformation(input);
myOutputs.Add(output);
Where is myOutputs defined? Well, where that state is maintained depends on a lot of things. This is a web application, so state can be an interesting thing. There are many places to maintain it:
Within the consuming method as a method-level variable
Within the consuming class as a class-level value
In session state
In a database
etc.
The overall flow of the logic and the application is going to govern this. For example, if a single instance of the class is maintaining the entire lifetime of this process then you would put it in a class-level value. However, if the value needs to persist across different page requests then you might want to put it in Session State instead. You have a number of options for where to maintain this collection of strings.
Try this:
PSEUDO CODE
public string[] GetInformation(int id)
{
List<string> oud = new List<string>();
oud.Add(id.ToString());
return oud.ToArray();
}
var myResult = GetInformation(1);
Console.WriteLine(string.Join(", ", myResult);
It's more nice to return unformatted data and format it when needed.
public int[] GetInformation(int id)
{
List<int> oud = new List<int>();
oud.Add(id);
return oud.ToArray();
}
var myResult = GetInformation(1);
Console.WriteLine(string.Join(", ", myResult);
Related
I'm currently writing logic to check if a given string that contains a certain range of values corresponding to certain criteria.
The logic I am trying to implement is as follows, there is a certain variable string value = "12"; with the assigned value as below, Given that I have a List of Values which I will have, I want to check if there will be any values with 12.x and this could be something like 12.0.1 or 12.2 Simply put want to check if the List contains anything with 12.Something (12 point something)
I have not been successful in how I can improve the said behavior Would really appreciate if someone has any idea if its possible to implement this
My code of the attempt is as follows:
static void Main(string[] args)
{
List<string> values = new List<string>();
values.Add("12.0.1");
values.Add("12.2");
string value = "12";
//Logic to check if values with 12.x / 12.something is available
}
Try this:
static void Main(string[] args)
{
List<string> values = new List<string>();
values.Add("12.0.1");
values.Add("12.2");
string value = "12";
var isExists = values.Any(x => x.StartsWith($"{value}."));
}
Try:
values.Where(v => v.StartsWith("12."));
This will return all values that meet the criteria. If you want to know how many there are, use Count instead of Where and if you only want to know if at least one value meets the criteria but you are not interested in the value itselft, use Any.
Use LINQ to Objects.
If you just want to check if the value presents in the list, you can write:
values.Any(e => e.StartsWith(value));
If you want to know, how many times the value presents in the list:
values.Count(e => e.StartsWith(value));
I have a list of integers (Levels). I want to initialize a nested Object of Filter called myFilter as below(Filter is a class with two properties: Value and NextFilter):
var myFilter = new Fliter{
Value = Levels[0],
NextFilter = new Filter{
Value = Levels[1],
NextFilter = new Filter{
Value = Levels[2],
NextFilter = new Filter{
Value = Levels[n],
NextFilter = null
}
}
}
}
Level's count is not static and depends on the input list (I have a multi select list that generates Level)
How can I do that?
This is a classic event for using - the technique of a method that calls itself:
public static Filter CreateFilter(List<int> values) => values.Any() ? new Filter //If the list contains elements, create the filter
{
Value = values.First(), //assign the first item of the values to the value property
NextFilter = CreateFilter(values.Skip(1).ToList()) //Create the rest of the nested object with the rest of the values
} : null; //If there aren't any items left in the list, return null and stop the recursion
You could of course do it in the constructor as well:
public Filter(List<int> values)
{
if (!values.Any()) return;
Value = values.First();
NextFilter = values.Count > 1 ? new Filter(values.Skip(1).ToList()) : null;
}
For more information about recursion, take a look at this: https://www.dotnetperls.com/recursion, for more information on nested classes read through this: https://www.dotnetperls.com/nested-class.
A few more information on recursion:
You can actually achieve everything through recursion - you don't even need loops. That's the reason why in languages like Haskell loops don't exist.
The simplest recursive function is:
public static void EndlessLoop()
{
//Loop body
EndlessLoop();
}
However, even Resharper suggests to convert it to a loop:
Another example, if you want to get the sum of a list you could do:
public static int Sum(List<int> summands) => summands.Count > 0
? summands.First() + Sum(summands.Skip(1).ToList())
: 0;
But those examples aren't useful in C#, as C# isn't a functional programming language, which causes recursion to be slower than loops. Furthermore recursion often causes a StackOverflowException (fitting to this site). If you run the endless loop recursion, it doesn't even take a second till your stack is full.
The reason for this is, that C# adds the address, from which a method got called, to the stack. If a method is called very often (and in 1 second a lot of recursive calls are made) a lot of addresses are added to the stack, so that it overflows.
However I still think, even though those examples aren't useful in c#, that it's quite useful to be able to handle recursion. Recursion is for example the only way to explore a directory structure, for getting for example all files:
public static List<FileInfo> GetAllFiles(DirectoryInfo directory) => directory.GetFiles()
.Concat(directory.GetDirectories().SelectMany(GetAllFiles))
.ToList();
And, as you experienced, it's the only way to fill a nested class from a list properly.
Just make a constructor of Filter, that will get Levels array as a parameter, that will set it's Value as level[0], and init NextFilter = new Filter(level.Skip(1)). Something like that. And it will recursively initialize your object.
In C#, I have a string array that I have written full full of "getter" method calls. They call methods in another class so that the array is populated with the needed strings. It looks something like this:
string[] mCalls = {c.get1(), c.get2(), c.get3()};
I'm sure this situation could apply to any program. However, in my program the variables these methods return are initially set with the string "Unchecked" - thus filling this example array with Unchecked 3 times. As my program goes on and things are checked, the values of the string variables get changed within the class they're in. I've been simply re-calling the getter methods at appropriate times to change what's in my array, like this:
mCalls[0] = c.get1();
mCalls[1] = c.get2();
mCalls[2] = c.get3();
I don't really like this. It seems inevitable that one day I'll have to change something, and if that happens I will have to manually do the tedious work of changing all of the indexing throughout my program. If this happens to be the best way I'm fine with that, but I assume there are better ways. So, in any case, is there a way to "refresh" the values in an array that is set up like this? And if so, what is it?
You want something like this:
public string[] MCalls
{
get
{
return new string[]{c.get1(), c.get2(), c.get3()};
}
private set;
}
and then use MCalls as if it is a regular variable whenever you want to access the arrays
You could change your array to contain functions instead of strings like this:
Func<string>[] mCalls = { c.get1, c.get2, c.get3...};
And then use it this way:
string c2 = mCalls[1]();
But note that this way every access is a method call. I'm not sure what you are really trying to achieve, there may be better overall designs than this approach.
Couple of options:
Create an array of lambdas:
var mCalls = new Func<object, string>[] {
(object o) => o.ToString() ,
(object o) => o.GetHashCode().ToString(),
(object o) => o.GetType().ToString(),
};
If the input to each lambda is the same you can create a lambda that returns an array:
Func<object, string[]> GetValues = (object o) => new string[]
{
o.ToString() ,
o.GetHashCode().ToString(),
o.GetType().ToString(),
};
Then just reload the array by calling the lambda:
mCalls = GetValues(c);
Note that it isn't technically refreshing the array, it's creating a new array. If you need to keep the array the same but just update the values you'd ned to loop through the array and assign the values by index.
What you could do is loop thorugh with reflection and get all methods from the class and from here you can get a list of method names. With this list you can assign to an array or run the methods by name or whatever. You can also filter the list to get your specific method names only:
var methodNames = typeof(MyClass).GetMethods(BindingFlags.Public | BindingFlags.Static)
.Select(x => x.Name)
.Distinct()
.OrderBy(x => x);
To call the methods:
foreach(var method in methodNames)
{
typeof(MyClass).GetMethod(method).Invoke(t, new[] { "world" });
}
I am trying to do some group comparison in my web application and want to see if the current user is in a certain list of groups that I have stored in a SQL table. I currently am getting my groups in an array using this method...
public ArrayList GetGroups()
{
ArrayList groups = new ArrayList();
foreach (System.Security.Principal.IdentityReference group in
System.Web.HttpContext.Current.Request.LogonUserIdentity.Groups)
{
groups.Add(group.Translate(typeof
(System.Security.Principal.NTAccount)).ToString());
}
return groups;
}
From here I can check if the user is in a certain group by doing this
ArrayList al = new ArrayList();
al = GetGroups();
foreach (string s in al)
{
if (s == "some_group")
{
//do this;
}
}
I can get it working for individual or even a few groups but I have a SQL table with about 20 groups in it and I just wanted to use some sort of comparison between the array and my SQL table. I tried using a dataset and comparing them but I was not able to get that working. Any advice is appreciated I am just learning how to work in C#. Thank you.
Few things I noticed from your code:
There is no reason to use ArrayList. Instead use a List<T> where in your case, T would be string. This provides type safety and better performance.
You create a new instance of the ArrayList class and then you assign the result of GetGroups to that variable (al). You initialized an instance of the ArrayList for no purpose, you already created the instance in the GetGroups method.
I'm not quite sure what comparison you are wanting to do between the user groups and the SQL groups. Feel free to add more details, but you can do a very basic contains check like so:
List<string> userGroups = GetUserGroups();
List<string> sqlGroups = GetSqlGroups();
foreach (var sqlGroup in sqlGroups)
{
// case-sensitive check
if (userGroups.Contains(sqlGroup))
{
// the user has one of the SQL groups
}
// case-insensitive check
if (userGroups.Contains(sqlGroup, StringComparer.OrdinalIgnoreCase))
{
// the user has one of the SQL groups
}
}
You can get more advanced using LINQ or even if you need to consider cAsE sEnsiTiviTY, but you'll need to provide more details for that.
List<string> userGroups = new List<string>();
List<string> sqlGroups = new List<string>();
var containedGroups = sqlGroups.Where(item=>userGroups.Contains(item));
Generic List is better than ArrayList if you can make sure your data type.
I'm trying to create a list of strings (on a controller method for use as JSON that is consumed by a JQuery Autocomplete on the client). Is there a way to reduce these six or seven lines to two lines? In other words I want the first line to create the IEnumerable of strings.
Also is there a way of not using the custom comparer - all it does is compare strings (on the CompanyMeasureName field).
public JsonResult GetMyMeasureNameList(string term)
{
//I've defined a custom comparer called NameComparer on the MyMeasure Object
IEnumerable<MyMeasure> interList =
MyMeasure.Distinct(new MyMeasure.NameComparer())
.Where(cmo => cmo.CompanyMeasureName
.ToLower()
.Contains(term.ToLower()));
List<string> retList = new List<string>();
foreach (var cmo in interList.ToList())
{
CompanyMeasure c = (CompanyMeasure)cmo;
retList.Add(c.CompanyMeasureName);
}
return Json(retList, JsonRequestBehavior.AllowGet);
}
Thanks in advance
The following solves part of the problem (as usual I came up with the answer 5 seconds after posting the question). However I'd still like to be able to not use a custom comparer as it seems pretty pointless.
IEnumerable<MyMeasure> interList =
MyMeasure.Distinct(new MyMeasure.NameComparer())
.Where(cmo => cmo.CompanyMeasureName
.ToLower()
.Contains(term.ToLower())).Select(m => m.CompanyMeasure);