Unable to remove empty strings in scala list - scala

Why none of these operations are working when I am trying to remove empty strings in my list?
This is my list:
(yuhindmklwm00409219,958193628,0305delete,2700)
(yuhindmklwm00409219,958193628,0305delete,800)
(yuhindmklwm00409219,959262446,0219delete,62)
()
(yuhindmklwm00437293,752013801,0220delete,2700)
()
()
()
(yuhindmklwm00437293,85382,0126delete,500)
()
(yuhindmklwm00437293,863056514,0326delete,-2700)
(yuhindmklwm00437293,863056514,0326delete,2700)
()
()
()
()
()
(yuhindmklwm00437293,85258,0313delete,1000)
(yuhindmklwm00437293,85012,0311delete,1000)
(yuhindmklwm00437293,85718,0311delete,2700)
()
()
()
()
()
()
()
(yuhindmklwm00437293,744622574,0322delete,90)
(yuhindmklwm00437293,83704,0215delete,17)
()
()
(yuhindmklwm00437293,85253,0331delete,-2700)
(yuhindmklwm00437293,85253,0331delete,2700)
()
()
()
()
()
()
()
()
(yuhindmklwm00437293,752013801,0305delete,2700)
(yuhindmklwm00437293,33165,0315delete,1000)
(yuhindmklwm00437293,85018,0319delete,100)
(yuhindmklwm00437293,85018,0219delete,100)
(yuhindmklwm00437293,85018,0118delete,100)
(yuhindmklwm00437293,90265,0312delete,6)
(yuhindmklwm00437293,02465,0312delete,25)
(yuhindmklwm00437293,857164939,0313delete,15)
(yuhindmklwm00437293,22102,0313delete,4)
(yuhindmklwm00437293,55423,0313delete,100)
(yuhindmklwm00437293,02465,0314delete,1)
(yuhindmklwm00437293,90265,0312delete,1)
(yuhindmklwm00437293,93108,0315delete,25)
(yuhindmklwm00437293,220432304,0315delete,35)
(yuhindmklwm00437293,701211570,0315delete,35)
(yuhindmklwm00437293,28801,0315delete,10)
(yuhindmklwm00437293,93108,0211delete,3)
(yuhindmklwm00437293,93108,02)
This is type of list:
List[String] = List((yuhindmklwm00437293,93108,02)..........))
I tried filter:
outputList1.filter(_.isNotNull).size
and
outputList1.map(record => if (record.size>3) record) else None)
both these approaches are unable to remove empty strings. The size of the list remains same for both

outputList1.filter(_.isNotNull).size
There is no such library method isNotNull and if there were this isn't what you want anyway because an empty string isn't the same thing as a null.
Besides that, it looks like you might not be dealing with actual empty strings. The string "()" is not empty. It has 2 characters in it. Try outputList1.filter(_.length > 2) (or whatever length is your actual limit).

Your first approach doesn't work because, as mentioned by jwvh, an empty string "" isn't null. Your code only filters out null strings.
Your second approach isn't giving you the expected result (i.e. expected length of result) because you are replacing the empty records with Nones. Replacing some items in a list with others, but not actually removing those items results in a list of the same size. None is an object, and can be one of the value of an Option type.
Some ways to achieve your desired result are:
outputList1.filter(_.nonEmpty)
Simple enough, filters out empty strings.
outputList1.map(record => if (record.nonEmpty) Some(record)) else None).flatten
A little more complex, this replaces every non empty record with Some(<record>) and every empty string with a None. The resultant List[Option[String]] (which is a mix of Somes and Nones, both Option types) can be easily flattened out using .flatten. This will extract the value from the Somes, and get rid of the Nones from the resultant list.
outputList1.collect(case record if (record.nonEmpty) => record) Collect works similar to map, expect it doesn't throw an exception in case of a match error with it's partial function.

Related

How to do a case insensitive match for command line arguments in scala?

I'm working on a command line tool written in Scala which is executed as:
sbt "run --customerAccount 1234567"
Now, I wish to make this flexible to accept "--CUSTOMERACCOUNT" or --cUsToMerAccount or --customerACCOUNT ...you get the drift
Here's what the code looks like:
lazy val OptionsParser: OptionParser[Args] = new scopt.OptionParser[Args]("scopt") {
head(
"XML Generator",
"Creates XML for testing"
)
help("help").text(s"Prints this usage message. $envUsage")
opt[String]('c', "customerAccount")
.text("Required: Please provide customer account number as -c 12334 or --customerAccount 12334")
.required()
.action { (cust, args) =>
assert(cust.nonEmpty, "cust is REQUIRED!!")
args.copy(cust = cust)
}
}
I assume the opt[String]('c', "customerAccount") does the pattern matching from the command line and will match with "customerAccount" - how do I get this to match with "--CUSTOMERACCOUNT" or --cUsToMerAccount or --customerACCOUNT? What exactly does the args.copy (cust = cust) do?
I apologize if the questions seem too basic. I'm incredibly new to Scala, have worked in Java and Python earlier so sometimes I find the syntax a little hard to understand as well.
You'd normally be parsing the args with code like:
OptionsParser.parse(args, Args())
So if you want case-insensitivity, probably the easiest way is to canonicalize the case of args with something like
val canonicalized = args.map(_.toLowerCase)
OptionsParser.parse(canonicalized, Args())
Or, if you for instance wanted to only canonicalize args starting with -- and before a bare --:
val canonicalized =
args.foldLeft(false -> List.empty[String]) { (state, arg) =>
val (afterDashes, result) = state
if (afterDashes) true -> (arg :: result) // pass through unchanged
else {
if (arg == "==") true -> (arg :: result) // move to afterDash state & pass through
else {
if (arg.startsWith("--")) false -> (arg.toLowerCase :: result)
else false -> (arg :: result) // pass through unchanged
}
}
}
._2 // Extract the result
.reverse // Reverse it back into the original order (if building up a sequence, your first choice should be to build a list in reversed order and reverse at the end)
OptionsParser.parse(canonicalized, Args())
Re the second question, since Args is (almost certainly) a case class, it has a copy method which constructs a new object with (most likely, depending on usage) different values for its fields. So
args.copy(cust = cust)
creates a new Args object, where:
the value of the cust field in that object is the value of the cust variable in that block (this is basically a somewhat clever hack that works with named method arguments)
every other field's value is taken from args

Get value from Instance in Flutter

I am making a search request on the List with the Provider pattern.
List<Device> _devices = [
Device(one: 'Apple', two: 'iphone'),
Device(one: 'Samsung', two: 'Galaxy')
];
And Query is like this
List<Device> queryQuery(String value) {
return _devices
.where((device) => device.one.toLowerCase().contains(value.toLowerCase()))
.toList();
the result I expect to get is iphone when I passed the value Apple.
But the result on the screen that I got is [instance of ‘Device’]
when I code like this
child: Text('${deviceData.getDevice('Apple')}'
I do know I should be using some kind of key using two... but I have no idea :-(
You serialized the wrong object.
What you did end-up being similar to:
Text(Device(one: 'Apple', two: 'iphone').toString());
But you don't want to do Device.toString(). What you want instead is to pass Device.two to your Text.
As such your end result is:
Text('${chordData.chordExpand('Apple').two}')
By the look of [Instance of 'Device'], it seems the function is returning a list so it is a good idea to check if the list is empty or not. if it is not empty, one of the elements is still needed to be selected. I guess it should be Text('${chordData.chordExpand('Apple')[0].two}') in case the list is not empty.
To summarize, use something like this to handle the case when list is empty
// Inside your build method before returning the widget
var l = chordData.chordExpand('Apple'); // Returns a list of devices
String textToWrite; // Here we will store the text that needs to be written
if(l.isEmpty) textToWrite = 'No results'; // If the filter resulted in an empty list
else textToWrite = l[0].two; // l[0] is an instance of a device which has a property called two. You can select any instance from the list provided it exists
return <Your Widget>(
.....
Text(textToWrite),
.....
);

Can't get first window of Rx's Window with FirstAsync

I want to separate an observable sequence (IObservable) into several observable sequences (the criteria is complicated, but for the sake of demonstration we can simply use count). This, quite obviously, calls for Window.
private static IObservable<int> GenerateSequence()
{
return Observable.Range(1, 5);
}
await GenerateSequence()
.Window(2)
.Select((w, i) => new {i, w})
.Do(w => w.w.Dump($"Window {w.i}"));
Output is as expected:
Window 0-->1
Window 0-->2
Window 0-->X
Window 1-->3
Window 1-->4
Window 1-->X
Window 2-->5
Window 2-->X
(X's mark the OnCompleted)
Now, for some reason I want only first of those sequences. Hence, FirstAsync:
(await GenerateSequence()
.Window(2)
.FirstAsync())
.Dump("Window");
But the strange thing is, I get no output at all, as if the sequence I get from FirstAsync was completely dead.
I'm kinda new to Rx, so I'm totally lost as to what and why exactly happens here.
EDIT:
Your answer works. You may want to look at replacing Window with Buffer. They're virtually identical, except Buffer was meant for similar scenarios. It returns a list though instead of array:
var t = GenerateSequence()
.Buffer(2)
.FirstAsync()
//.Select(list => list.ToArray()) //If you're particular about Task<int[]> over Task<IList<int>>
.ToTask();
As another aside, .SelectMany(i => i) can be replaced with .Merge().
Old answer:
I generally don't mix Rx with await. It's apparently supported, but seems... unintuitive. This code dumps the output of the first window:
GenerateSequence()
.Window(2)
.FirstAsync()
.Subscribe(i => i.Dump("Window"));
This dumps the first item from each window:
GenerateSequence()
.Window(2)
.Select(o => o.FirstAsync())
.Subscribe(i => i.Dump("Window"));
It wasn't clear from your question which one you wanted.
Actually, the solution was quite simple (although I still don't get what happens in my original code) - use SelectMany to flatten the sequence:
GenerateSequence()
.Window(2)
.FirstAsync()
.Concat()
.Dump("SO");
Produces, as expected:
SO-->1
SO-->2
SO-->X
And then, to achieve my original goal - i.e., to change the monad and return the result as Task<int[]>:
GenerateSequence()
.Window(2)
.FirstAsync()
.Concat()
.ToArray()
.ToTask();

What's wrong with my Meteor publication?

I have a publication, essentially what's below:
Meteor.publish('entity-filings', function publishFunction(cik, queryArray, limit) {
if (!cik || !filingsArray)
console.error('PUBLICATION PROBLEM');
var limit = 40;
var entityFilingsSelector = {};
if (filingsArray.indexOf('all-entity-filings') > -1)
entityFilingsSelector = {ct: 'filing',cik: cik};
else
entityFilingsSelector = {ct:'filing', cik: cik, formNumber: { $in: filingsArray} };
return SB.Content.find(entityFilingsSelector, {
limit: limit
});
});
I'm having trouble with the filingsArray part. filingsArray is an array of regexes for the Mongo $in query. I can hardcode filingsArray in the publication as [/8-K/], and that returns the correct results. But I can't get the query to work properly when I pass the array from the router. See the debugged contents of the array in the image below. The second and third images are the client/server debug contents indicating same content on both client and server, and also identical to when I hardcode the array in the query.
My question is: what am I missing? Why won't my query work, or what are some likely reasons it isn't working?
In that first screenshot, that's a string that looks like a regex literal, not an actual RegExp object. So {$in: ["/8-K/"]} will only match literally "/8-K/", which is not the same as {$in: [/8-K/]}.
Regexes are not EJSON-able objects, so you won't be able to send them over the wire as publish function arguments or method arguments or method return values. I'd recommend sending a string, then inside the publish function, use new RegExp(...) to construct a regex object.
If you're comfortable adding new methods on the RegExp prototype, you could try making RegExp an EJSON-able type, by putting this in your server and client code:
RegExp.prototype.toJSONValue = function () {
return this.source;
};
RegExp.prototype.typeName = function () {
return "regex";
}
EJSON.addType("regex", function (str) {
return new RegExp(str);
});
After doing this, you should be able to use regexes as publish function arguments, method arguments and method return values. See this meteorpad.
/8-K/.. that's a weird regex. Try /8\-K/.
A minus (-) sign is a range indicator and usually used inside square brackets. The reason why it's weird because how could you even calculate a range between 8 and K? If you do not escape that, it probably wouldn't be used to match anything (thus your query would not work). Sometimes, it does work though. Better safe than never.
/8\-K/ matches the string "8-K" anywhere once.. which I assume you are trying to do.
Also it would help if you would ensure your publication would always return something.. here's a good area where you could fail:
if (!cik || !filingsArray)
console.error('PUBLICATION PROBLEM');
If those parameters aren't filled, console.log is probably not the best way to handle it. A better way:
if (!cik || !filingsArray) {
throw "entity-filings: Publication problem.";
return false;
} else {
// .. the rest of your publication
}
This makes sure that the client does not wait unnecessarily long for publications statuses as you have successfully ensured that in any (input) case you returned either false or a Cursor and nothing in between (like surprise undefineds, unfilled Cursors, other garbage data.

Getting an "Odd number of elements in hash assignment" error

I'm getting the following error when running a Perl script
Odd number of elements in hash assignment at GenerateInterchangeFromIntegrationManifest.pl line 197.
{
"Change list" : "0"
}
This is the script:
my %labelFieldMap = (IUItemName => convertIuItemName,
Changelist => sub {},
IUItemLevel => createNormalConvert('iuItemLevel'),
ContactPOC => \&convertContacts,
Cspec => \&convertCspec,
IsNew => createBooleanConvert('isNew'),
Submitter => createNormalConvert('submitter'),
LabelType => createNormalConvert('type'),
Revision => createNestedConvert('component', 'revision'),
RevisionName => sub {},
ComponentBaseName => createNestedConvert('component', 'baseName'),
Version => createNestedConvert('component', 'version'),
PLMapping => createNormalConvert('plMapping'),
BidMapping => createNormalConvert('bidMapping'),
ClientId => createNormalConvert('clientId'),
Path => \&convertPath,
ExtendedData => \&convertExtendedData);
Can any one help me resolve this issue?
There are several subroutine calls in assignment to the hash that could be returning lists with an even number of elements (which would make the list count odd overall, and also change which data is keys and which values from that point in the list on, which is probably worse for you). As Dallaylaen has pointed out in comments, this could simply be a line which returns "nothing", return; which will evaluate to empty list (), i.e. an even length of 0, in list context. All the subroutine calls in the question code will be evaluated in list context.
I would suggest a simple debug technique:
Comment out all the lines with a function call, that should remove the warning.
Then add back a few at a time and re-test.
When the warning re-appears, you will have isolated the problem to one of a few subroutines.
Repeat until you know which one.
Then investigate that call to see how you might fix it.