I want to change Map values using java 8.
Map<String, String> attributeMap = new TreeMap<>();
attributeMap.put("C","FIRSTNAMe");
attributeMap.put("C3","1111");
attributeMap.put("C4","ABCNAMe");
After the changes, the output as a string should look like
c='FIRSTNAMe',c3=111,c4='ABCNAMe'
Can anyone help me.
You could create a method transform and pass a Predicate for when to quote or not:
public static String tranform(Map<String, String> attributeMap, Predicate<String> predicate) {
return attributeMap.entrySet()
.stream()
.collect(Collectors.mapping(e -> {
return e.getKey().toLowerCase() + "=" +
(predicate.test(e.getValue()) ? "'" + e.getValue() + "'" : e.getValue());
}, Collectors.joining(",")));
}
And call it like this:
String result = tranform(attributeMap, "1111"::equals);
System.out.println(result); // c=FIRSTNAMe,c3='1111',c4=ABCNAMe
If you want to quote only numbers, just use a different Predicate:
Predicate<String> predicate = s -> s.matches("\\d+");
String result = tranform(attributeMap, predicate);
Related
private val BASE_URL = "https://itunes.apple.com/search?"
private var iTunesMap = mutableMapOf("term" to "parameter1",
"media" to "parameter2")
fun URL.addParameters(map:Map<String,String>) : String {
var newURL = BASE_URL
for(parameter in iTunesMap.iterator())
{
newURL += parameter.key + "=" + parameter.value + "&"
}
return newURL
}
I am ending up with a & at the end of the URL.
How do I prevent this from happening?
You can simply do it in a functional way:
val parameters = map.map { (key, value) -> // 1
"$key=$value" // 2
}.joinToString("&") // 3
return BASE_URL + parameters // 4
Explenation:
We use map function with destructuring declaration of parameters (key, value) which correspond to key and value in each map entry
For each map entry we create string key=value ($ is indicator, that we want to use value of some variable - in that case we use value of parameter key and parameter value
After .map function we have collection of strings: term=parameter1 and media=parameter2, we are joining them with & separator
Lastly we need to concatenate parameters to base url
If I can suggest - I would make this function more general by putting baseUrl as parameter - then you can use the same function for different urls.
EDIT
As Михаил Нафталь suggested in his answer, you can add prefix to joinToString function so you don't have to concatenate parameters with base url. So after that improvement your code will look like this:
return map.map { (key, value) ->
"$key=$value"
}.joinToString("&", prefix = BASE_URL )
Or you can do all of this using just joinToString function with giving transform function. (look for Михаил Нафталь answer)
Here is a one-liner:
map.entries.joinToString(separator = "&", prefix = BASE_URL) { (key, value) -> "$key=$value" }
Strings are immutable and += involves copying the entire string into a new string. Do not use += on a var: String in a loop, as that is O(N²); use a StringBuilder instead.
val urlBuilder = StringBuilder(BASE_URL)
iTunesMap.entries.joinTo(urlBuilder, separator = "&") { (key, value) ->
"$key=$value"
}
return urlBuilder.toString()
I am working on creating a simple java class which would give me used & unused css on any given page.
public class coverage {
static String str;
public static void main(String[] args) throws JSONException {
String url = "https://www.amazon.com";
Launcher launcher = new Launcher();
try (SessionFactory factory = launcher.launch();
Session session = factory.create()) {
Command command = session.getCommand();
DOM dom = command.getDOM();
CSS css = command.getCSS();
session.navigate(url);
dom.enable();
css.enable();
HashMap<String, List<String>> hm = new HashMap<String, List<String>>();
HashMap<String, String> hmUsedCSS = new HashMap<String, String>();
css.startRuleUsageTracking();
List<RuleUsage> list = css.stopRuleUsageTracking();
for (RuleUsage coverage : list) {
if (!hm.containsKey(coverage.getStyleSheetId())) {
hm.put(coverage.getStyleSheetId(),
css.collectClassNames(coverage.getStyleSheetId()));
}
if (!coverage.isUsed()) {
String existingContent = hmUsedCSS.get(coverage
.getStyleSheetId());
String extraContent = css.getStyleSheetText(coverage
.getStyleSheetId());
hmUsedCSS.put(coverage.getStyleSheetId(),
existingContent == null ? extraContent
: existingContent + extraContent);
}
}
for (String name : hm.keySet()) {
List<String> value = hm.get(name);
System.out.println("Total " + name + "=>" + value);
}
for (String name : hmUsedCSS.keySet()) {
List<String> value = hm.get(name);
System.out.println("Used CSS " + name + "=>" + value);
}
}
}
}
As per official documentation, 'stopRuleUsageTracking' would tell us whether a particular CSS is being used or not by setting 'used' boolean in RuleUsage , but it is returning all the CSS available on the page with 'used' set to true.I figured out that the answer lies in startoffset & endoffset values as they tell us the positioning of used CSS.But I don't know how to convert these values into meaningful result of Used & Unused CSS ? Can someone help me out here?
As I pointed out in the question , the key was to fetch coverage data as per start & end offset values.I was able to write logic to do the same & got the required list of used & Unused CSS.
In a db table I have a string, such as...
Var1=0;CosType=1;DefaultType=US_Pass;DateYear=1;DateRange=1;ReportFormat=0
I want to create a VB.NET function that has 1 input var, the string (above) and the "token" to get the value for. (The return value is the value of the token.) For example, if I call it (LongString is the string above)....
txtValue.text = MyFunction(LongString,"DefaultType")
So, "US_Pass" would be returned.
What is the most efficient way to code MyFunction?
I've tried something like this...
return LongString.Substring(LongString.IndexOf(input_token) + 12)
I feel I'm close, but so far away.
Thanks!
This works as long as you know the key exists in your string:
public string MyFunction(string longString, string key)
{
return
longString
.Split(';')
.Select(x => x.Split('='))
.ToDictionary(x => x[0], x => x[1])[key];
}
With this code:
string longString = "Var1=0;CosType=1;DefaultType=US_Pass;DateYear=1;DateRange=1;ReportFormat=0";
Console.WriteLine(MyFunction(longString, "DefaultType"));
I get:
US_Pass
As VB.NET:
Public Function MyFunction(longString As String, key As String) As String
Return longString.Split(";"c).Select(Function(x) x.Split("="c)).ToDictionary(Function(x) x(0), Function(x) x(1))(key)
End Function
Split the string into parts at the semi-colons.
Dim parts As String() = LongString.Split(";")
Loop over the parts in a ForEach loop.
Find the part that StartsWith the the token value.
Find the equal sign (IndexOf) and take everything to the right of it (Substring).
That should give you enough to figure it out.
It's probably not a great idea to store data like this in your database. Hopefully you won't need to query these attributes from SQL.
In your case I would create a class to encapsulate the attributes. You pass in the string as a constructor parameter and let the class manage it.
Here's an example in C# that shouldn't be too hard to convert to VB:
public class AttributeCollection
{
private readonly Dictionary<string, string> _attrs;
public AttributeCollection(string values)
{
_attrs = (from v in values.Split(new[] {';'})
select v.Split(new[] {'='})).ToDictionary(i => i[0], i => i[1]);
}
public string this[string name]
{
get { return _attrs[name]; }
set { _attrs[name] = value; }
}
public override string ToString()
{
return string.Join(";", (from a in _attrs select a.Key + "=" + a.Value).ToArray());
}
}
I'm retrieving a string array of files and I would like to custom sort them by a substring in the file name...using C# **.NET 3.5. Below is what I am working with.
<% string[] files = System.IO.Directory.GetFiles("...path..." + pageName + "\\reference\\");
files = String.Join(",", files).Replace("...path...", "").Replace("\\reference\\", "").Replace(pageName, "").Split(new Char[] { ',' });
foreach (String item in files)
{
Response.Write("<a href=" + pageName + "/reference/" + System.IO.Path.GetFileName(item) + " target='_blank'>" + item.Replace("_", " ").Replace(".pdf", " ") + "</a>");
}
%>
I'm a C# noob, and I don't know where to go from here. Basically, I'm looking for a substring in the file name to determine the order (e.g., "index","reference","list"; where any file including the string "index" would be listed first). Perhaps there is a better way to do it. Any help would be appreciated.
You can use Linq to order the array by the filenames. In general, use the Path class if you're working with paths.
string fullPath = Path.Combine(directory, pageName, "reference");
var filePaths = Directory.EnumerateFiles(fullPath, "*.*", SearchOption.TopDirectoryOnly)
.Select(fp => new{ FullPath = fp, FileName=Path.GetFileName(fp) })
.OrderByDescending(x => x.FileName.IndexOf("index", StringComparison.OrdinalIgnoreCase) >= 0)
.ThenByDescending(x => x.FileName.IndexOf("reference", StringComparison.OrdinalIgnoreCase) >= 0)
.ThenByDescending(x => x.FileName.IndexOf("list", StringComparison.OrdinalIgnoreCase) >= 0)
.ThenBy(x=> x.FileName)
.Select(x => x.FullPath);
foreach(string filePath in filePaths)
;// ...
If you don't want to compare case-insensitively (so that "index" and "Index" are considered the same) use String.Contains instead of String.IndexOf + StringComparison.OrdinalIgnoreCase.
Here's an easy way I use when I run into this problem.
Define the order of the substrings in a list. Then for each item, check to see whats the first thing that contains that item. Then sort by the order of the substring in the list.
public class SubStringSorter : IComparer<string>
{
public int Compare(string x, string y)
{
var source = x.ToLowerInvariant();
var target = y.ToLowerInvariant();
var types = new List<string> { "base", "data", "model", "services", "interceptor", "controllers", "directives", "filters", "app", "tests", "unittests" };
var sourceType = types.IndexOf(types.FirstOrDefault(source.Contains));
var targetType = types.IndexOf(types.FirstOrDefault(target.Contains));
return sourceType.CompareTo(targetType);
}
}
To sort your files, do something like
var list = new List<string>{ "baseFile", "servicesFile", "this ModElstuff" };
list.Sort(new SubStringSorter());
And the output
You could even go one step further and give the substring sorter the list as part of its constructor so you can re-use the substring sort order with other items. The example I posted tests if the string exists in any context, but if you are more interested in it starting with a string you can do that too.
I know i can do this
var nv = HttpUtility.ParseQueryString(req.RawUrl);
But is there a way to convert this back to a url?
var newUrl = HttpUtility.Something("/page", nv);
Simply calling ToString() on the NameValueCollection will return the name value pairs in a name1=value1&name2=value2 querystring ready format. Note that NameValueCollection types don't actually support this and it's misleading to suggest this, but the behavior works here due to the internal type that's actually returned, as explained below.
Thanks to #mjwills for pointing out that the HttpUtility.ParseQueryString method actually returns an internal HttpValueCollection object rather than a regular NameValueCollection (despite the documentation specifying NameValueCollection). The HttpValueCollection automatically encodes the querystring when using ToString(), so there's no need to write a routine that loops through the collection and uses the UrlEncode method. The desired result is already returned.
With the result in hand, you can then append it to the URL and redirect:
var nameValues = HttpUtility.ParseQueryString(Request.QueryString.ToString());
string url = Request.Url.AbsolutePath + "?" + nameValues.ToString();
Response.Redirect(url);
Currently the only way to use a HttpValueCollection is by using the ParseQueryString method shown above (other than reflection, of course). It looks like this won't change since the Connect issue requesting this class be made public has been closed with a status of "won't fix."
As an aside, you can call the Add, Set, and Remove methods on nameValues to modify any of the querystring items before appending it. If you're interested in that see my response to another question.
string q = String.Join("&",
nvc.AllKeys.Select(a => a + "=" + HttpUtility.UrlEncode(nvc[a])));
Make an extension method that uses a couple of loops. I prefer this solution because it's readable (no linq), doesn't require System.Web.HttpUtility, and it supports duplicate keys.
public static string ToQueryString(this NameValueCollection nvc)
{
if (nvc == null) return string.Empty;
StringBuilder sb = new StringBuilder();
foreach (string key in nvc.Keys)
{
if (string.IsNullOrWhiteSpace(key)) continue;
string[] values = nvc.GetValues(key);
if (values == null) continue;
foreach (string value in values)
{
sb.Append(sb.Length == 0 ? "?" : "&");
sb.AppendFormat("{0}={1}", Uri.EscapeDataString(key), Uri.EscapeDataString(value));
}
}
return sb.ToString();
}
Example
var queryParams = new NameValueCollection()
{
{ "order_id", "0000" },
{ "item_id", "1111" },
{ "item_id", "2222" },
{ null, "skip entry with null key" },
{ "needs escaping", "special chars ? = &" },
{ "skip entry with null value", null }
};
Console.WriteLine(queryParams.ToQueryString());
Output
?order_id=0000&item_id=1111&item_id=2222&needs%20escaping=special%20chars%20%3F%20%3D%20%26
This should work without too much code:
NameValueCollection nameValues = HttpUtility.ParseQueryString(String.Empty);
nameValues.Add(Request.QueryString);
// modify nameValues if desired
var newUrl = "/page?" + nameValues;
The idea is to use HttpUtility.ParseQueryString to generate an empty collection of type HttpValueCollection. This class is a subclass of NameValueCollection that is marked as internal so that your code cannot easily create an instance of it.
The nice thing about HttpValueCollection is that the ToString method takes care of the encoding for you. By leveraging the NameValueCollection.Add(NameValueCollection) method, you can add the existing query string parameters to your newly created object without having to first convert the Request.QueryString collection into a url-encoded string, then parsing it back into a collection.
This technique can be exposed as an extension method as well:
public static string ToQueryString(this NameValueCollection nameValueCollection)
{
NameValueCollection httpValueCollection = HttpUtility.ParseQueryString(String.Empty);
httpValueCollection.Add(nameValueCollection);
return httpValueCollection.ToString();
}
Actually, you should encode the key too, not just value.
string q = String.Join("&",
nvc.AllKeys.Select(a => $"{HttpUtility.UrlEncode(a)}={HttpUtility.UrlEncode(nvc[a])}"));
Because a NameValueCollection can have multiple values for the same key, if you are concerned with the format of the querystring (since it will be returned as comma-separated values rather than "array notation") you may consider the following.
Example
var nvc = new NameValueCollection();
nvc.Add("key1", "val1");
nvc.Add("key2", "val2");
nvc.Add("empty", null);
nvc.Add("key2", "val2b");
Turn into: key1=val1&key2[]=val2&empty&key2[]=val2b rather than key1=val1&key2=val2,val2b&empty.
Code
string qs = string.Join("&",
// "loop" the keys
nvc.AllKeys.SelectMany(k => {
// "loop" the values
var values = nvc.GetValues(k);
if(values == null) return new[]{ k };
return nvc.GetValues(k).Select( (v,i) =>
// 'gracefully' handle formatting
// when there's 1 or more values
string.Format(
values.Length > 1
// pick your array format: k[i]=v or k[]=v, etc
? "{0}[]={1}"
: "{0}={1}"
, k, HttpUtility.UrlEncode(v), i)
);
})
);
or if you don't like Linq so much...
string qs = nvc.ToQueryString(); // using...
public static class UrlExtensions {
public static string ToQueryString(this NameValueCollection nvc) {
return string.Join("&", nvc.GetUrlList());
}
public static IEnumerable<string> GetUrlList(this NameValueCollection nvc) {
foreach(var k in nvc.AllKeys) {
var values = nvc.GetValues(k);
if(values == null) { yield return k; continue; }
for(int i = 0; i < values.Length; i++) {
yield return
// 'gracefully' handle formatting
// when there's 1 or more values
string.Format(
values.Length > 1
// pick your array format: k[i]=v or k[]=v, etc
? "{0}[]={1}"
: "{0}={1}"
, k, HttpUtility.UrlEncode(values[i]), i);
}
}
}
}
As has been pointed out in comments already, with the exception of this answer most of the other answers address the scenario (Request.QueryString is an HttpValueCollection, "not" a NameValueCollection) rather than the literal question.
Update: addressed null value issue from comment.
The short answer is to use .ToString() on the NameValueCollection and combine it with the original url.
However, I'd like to point out a few things:
You cant use HttpUtility.ParseQueryString on Request.RawUrl. The ParseQueryString() method is looking for a value like this: ?var=value&var2=value2.
If you want to get a NameValueCollection of the QueryString parameters just use Request.QueryString().
var nv = Request.QueryString;
To rebuild the URL just use nv.ToString().
string url = String.Format("{0}?{1}", Request.Path, nv.ToString());
If you are trying to parse a url string instead of using the Request object use Uri and the HttpUtility.ParseQueryString method.
Uri uri = new Uri("<THE URL>");
var nv = HttpUtility.ParseQueryString(uri.Query);
string url = String.Format("{0}?{1}", uri.AbsolutePath, nv.ToString());
I always use UriBuilder to convert an url with a querystring back to a valid and properly encoded url.
var url = "http://my-link.com?foo=bar";
var uriBuilder = new UriBuilder(url);
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
query.Add("yep", "foo&bar");
uriBuilder.Query = query.ToString();
var result = uriBuilder.ToString();
// http://my-link.com:80/?foo=bar&yep=foo%26bar
In AspNet Core 2.0 you can use QueryHelpers AddQueryString method.
As #Atchitutchuk suggested, you can use QueryHelpers.AddQueryString in ASP.NET Core:
public string FormatParameters(NameValueCollection parameters)
{
var queryString = "";
foreach (var key in parameters.AllKeys)
{
foreach (var value in parameters.GetValues(key))
{
queryString = QueryHelpers.AddQueryString(queryString, key, value);
}
};
return queryString.TrimStart('?');
}
This did the trick for me:
public ActionResult SetLanguage(string language = "fr_FR")
{
Request.UrlReferrer.TryReadQueryAs(out RouteValueDictionary parameters);
parameters["language"] = language;
return RedirectToAction("Index", parameters);
}
You can use.
var ur = new Uri("/page",UriKind.Relative);
if this nv is of type string you can append to the uri first parameter.
Like
var ur2 = new Uri("/page?"+nv.ToString(),UriKind.Relative);