I have a FeatureCollection with a column named Dominance which has classified regions into stakeholder dominance. In this case, Dominance contains values as strings; specifically 'Small', 'Medium', 'Large' and 'Others'.
I want to replace these values/strings with 1,2,3 and 4. For that, I use the codes below:
var Shape = ee.FeatureCollection('XYZ')
var Shape_custom = Shape.select(['Dominance'])
var conditional = function(feat) {
return ee.Algorithms.If(feat.get('Dominance').eq('Small'),
feat.set({class: 1}),
feat)
}
var test = Shape_custom.map(conditional)
## This I plan to repeat for all classes
However, I am not able to change the values. The error I am getting is feat.get(...).eq is not a function.
What am I doing wrong here?
The simplest way to do this kind of mapping is using a dictionary. That way you do not need more code for each additional case.
var mapping = ee.Dictionary({
'Small': 1,
'Medium': 2,
'Large': 3,
'Others': 4
});
var mapped = Shape
.select(['Dominance'])
.map(function (feature) {
return feature.set('class', mapping.get(feature.get('Dominance')));
});
https://code.earthengine.google.com/8c58d9d24e6bfeca04e2a92b76d623a2
In Google Sheets, I'm trying to query a column and look for a state abbreviation, and if that abbreviation is a match, then "East" if not then "West"
Wanting to return text values in my column based on state abbreviation. We have territory manager split into two domains--East and West. So, trying to easily sort my data by East/West.
Here's what I have:
=IF(M:M={"AL", "CA", "DE","FL","GA","IA","KY","ME","MD","MA","MN","MS","NH","NJ","NY","ND","RI","SD","TN","VT","VA","WV","WI"},"East","West")
But, when I fill down, it just fills down East, and does not seem to actually query M:M
Thoughts?
Not the cleanest code, but this should work:
=ARRAYFORMULA(IF(LEN(A:A), IF((A:A = "foo")+(A:A = "bar") = 1, "WEST", "EAST"), ))
To use IF with an OR in an ARRAYFORMULA, you evaluate the column with 1s and 0s. The A:A = "foo" will evaluate to 1 if foo is in the cell. So if one of your OR criteria is in the cell, the total value in the IF will be 1.
You have a lot of criteria so writing each of them in will take a while ...
E.g. IF( (A:A = "AL") + (A:A = "CA") ... (A:A = "WI") = 1, "East", "West")
Use ISERROR/MATCH():
=IF(ISERROR(MATCH(M:M,{"AL", "CA", "DE","FL","GA","IA","KY","ME","MD","MA","MN","MS","NH","NJ","NY","ND","RI","SD","TN","VT","VA","WV","WI"},0)),"West","East")
Is it possible to define an interface which has some information on the format of a string? Take the following example:
interface timeMarkers{
markerTime: string[]
};
an example would be:
{
markerTime: ["0:00","1:30", "1:48"]
}
My question: Is there a way to define the type for markerTime such that that the string value must always match this regex, instead of declaring it as simply string[] and going from there?
var reg = /[0-9]?[0-9]:[0-9][0-9]/;
There is no way to define such a type. There is a proposal on GitHub to support this, but it currently does not appear to be a priority. Vote on it and maybe the team might include it in a future release.
Edit
Starting in 4.1 you can define a type that would validate the string without actually defining all the options:
type MarkerTime =`${number| ''}${number}:${number}${number}`
let a: MarkerTime = "0-00" // error
let b: MarkerTime = "0:00" // ok
let c: MarkerTime = "09:00" // ok
Playground Link
Until regex types become available to the language, you can now use template literal types in TS 4.1.
Let me refer to the question example and illustrate, how to model a time restricted string type called Time. Time expects strings in the format hh:mm (e.g. "23:59") here for simplification.
Step 1: define HH and MM types
Paste following code into your browser web console:
Array.from({length:24},(v,i)=> i).reduce((acc,cur)=> `${acc}${cur === 0 ? "" : "|"}'${String(cur).padStart(2, 0)}'`, "type HH = ")
Array.from({length:60},(v,i)=> i).reduce((acc,cur)=> `${acc}${cur === 0 ? "" : "|"}'${String(cur).padStart(2, 0)}'`, "type MM = ")
Generated result, which we can use as types in TS:
type HH = '00'|'01'|'02'|'03'|'04'|'05'|'06'|'07'|...|'22'|'23'
type MM = '00'|'01'|'02'|'03'|'04'|'05'|'06'|'07'|...|'58'|'59'
Step 2: Declare Time
type Time = `${HH}:${MM}`
Simple as that.
Step 3: Some testing
const validTimes: Time[] = ["00:00","01:30", "23:59", "16:30"]
const invalidTimes: Time[] = ["30:00", "23:60", "0:61"] // all emit error
Here is a live code example to get play around with Time.
type D1 = 0|1;
type D3 = D1|2|3;
type D5 = D3|4|5;
type D9 = D5|6|7|8|9;
type Hours = `${D9}` | `${D1}${D9}` | `2${D3}`;
type Minutes = `${D5}${D9}`;
type Time = `${Hours}:${Minutes}`;
Compact solution aggregating ideas from #bela53 and #yoel halb.
This solution has 2039 enum members for the Time type.
Ts Playground
Basing on the answer of #bela53 but much more simpler, we can do a very simple solution which is similar to what #Titian but without the drawbacks:
type HourPrefix = '0'|'1'|'2';
type MinutePrefix = HourPrefix | '3'|'4'|'5';
type Digit = MinutePrefix |'6'|'7'|'8'|'9';
type Time = `${HourPrefix | ''}${Digit}:${MinutePrefix}${Digit}`
const validTimes: Time[] = ["00:00","01:30", "23:59", "16:30"]
const invalidTimes: Time[] = ["30:00", "23:60", "0:61"] // all emit error
WARNING: There is a limit to what TypeScript can handle with #bela53 approach...
Based upon #bela53's answer I attempted the following type definition for an IPv4 address that results in "TS2590: Expression produces a union type that is too complex to represent." This definition caused IntelliJ to consume lots and lots of CPU time when I ignored the TypeScript error and tried to build anyway on the premise that it was still valid (I ended up needing to kill and restart IntelliJ).
type segment = '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'|'10'|'11'|'12'|'13'|'14'|'15'|'16'|'17'|'18'|'19'|'20'|'21'|'22'|'23'|'24'|'25'|'26'|'27'|'28'|'29'|'30'|'31'|'32'|'33'|'34'|'35'|'36'|'37'|'38'|'39'|'40'|'41'|'42'|'43'|'44'|'45'|'46'|'47'|'48'|'49'|'50'|'51'|'52'|'53'|'54'|'55'|'56'|'57'|'58'|'59'|'60'|'61'|'62'|'63'|'64'|'65'|'66'|'67'|'68'|'69'|'70'|'71'|'72'|'73'|'74'|'75'|'76'|'77'|'78'|'79'|'80'|'81'|'82'|'83'|'84'|'85'|'86'|'87'|'88'|'89'|'90'|'91'|'92'|'93'|'94'|'95'|'96'|'97'|'98'|'99'|'100'|'101'|'102'|'103'|'104'|'105'|'106'|'107'|'108'|'109'|'110'|'111'|'112'|'113'|'114'|'115'|'116'|'117'|'118'|'119'|'120'|'121'|'122'|'123'|'124'|'125'|'126'|'127'|'128'|'129'|'130'|'131'|'132'|'133'|'134'|'135'|'136'|'137'|'138'|'139'|'140'|'141'|'142'|'143'|'144'|'145'|'146'|'147'|'148'|'149'|'150'|'151'|'152'|'153'|'154'|'155'|'156'|'157'|'158'|'159'|'160'|'161'|'162'|'163'|'164'|'165'|'166'|'167'|'168'|'169'|'170'|'171'|'172'|'173'|'174'|'175'|'176'|'177'|'178'|'179'|'180'|'181'|'182'|'183'|'184'|'185'|'186'|'187'|'188'|'189'|'190'|'191'|'192'|'193'|'194'|'195'|'196'|'197'|'198'|'199'|'200'|'201'|'202'|'203'|'204'|'205'|'206'|'207'|'208'|'209'|'210'|'211'|'212'|'213'|'214'|'215'|'216'|'217'|'218'|'219'|'220'|'221'|'222'|'223'|'224'|'225'|'226'|'227'|'228'|'229'|'230'|'231'|'232'|'233'|'234'|'235'|'236'|'237'|'238'|'239'|'240'|'241'|'242'|'243'|'244'|'245'|'246'|'247'|'248'|'249'|'250'|'251'|'252'|'253'|'254'|'255';
export type ipAddress = `${segment}.${segment}.${segment}.${segment}`;
I'm not sure if there is any workaround for this.
For MySQL date/time strings
I was trying to make a type that reflected MySQL datetime string values ie "2022-07-31 23:11:54".
Interestingly, you can almost do it currently, but if you add any more specificity it will end up either being any or complain that it can't add more typing. I think there is limit to the # of typings it can create?
type OneToNine = 1|2|3|4|5|6|7|8|9
type ZeroToNine = 0|1|2|3|4|5|6|7|8|9
export type DateTimeType = `${
`${number}`
}-${
`0${OneToNine}` | `1${0|1|2}`
}-${
`0${OneToNine}` | `1${ZeroToNine}` | `2${ZeroToNine}` | `3${0|1}`
} ${
`0${OneToNine}` | `1${0|OneToNine}` | `2${0|1|2|3}`
}:${number}:${number}`
I was just looking for a similar feature right now, too!
And I ended up thinking about this:
Would'nt it be possible to get this running by setting up a little more complex dev-environment? Maybe you could use a file-watcher to trigger tsc and look up TypeError events to update your *d.ts file.
I mean something like:
export type superRegexType = 'type-1' | 'type-2' | '/type-/';
and as a hook something (rudimental suggestion):
const onTypeError = (err: Error, nameOfTypeSuperRegexType: string) => {
const myTypesFile = require('fs').readFileSync(`path/to/\*d.ts`) as string;
const searchFor = `export type ${nameOfTypeSuperRegexType} =`;
const getDefinition = (inMyTypesFile: string, searchFor: string) => {
const typeDefinitionString = inMyTypesFile.split(searchFor)[0].split(';')[0] + ';';
const stringsInThere = typeDefinitionString.split(' | ').map(_str => _str.trim());
const myRegexStr = stringsInThere.pop();
return {
oldTypeDefinitionString: typeDefinitionString,
stringsInThere,
myRegexStr,
myRegex: new RegExp(myRegexStr)
};
};
const myTypeDefinition = getDefinition(myTypesFile, searchFor);
const shouldDynamicallyAddType = myTypeDefinition.myRegex.exec(err.message);
if (!shouldDynamicallyAddType) {
console.log("this is a real TypeError");
console.error(err);
return;
} else {
const indexInErrMessage = shouldDynamicallyAddType.index;
const _endIdx = err.message.indexOf('\'');
const typeToAdd = err.message.slice(indexInErrMessage, _endIdx).trim();
myTypeDefinition.stringsInThere.push(typeToAdd);
const updatedTypeDefinitionString = `${searchFor} ${myTypeDefinition.stringsInThere.join(' | ')} ${myTypeDefinition.myRegexStr};`;
myTypesFile.replace(myTypeDefinition.oldTypeDefinitionString, updatedTypeDefinitionString);
// --> save that new d.ts and return hopefully watch the lint-error disappearing
}
}
Maybe this kind of solution would allow you to dynamically add types based on your RegEx on compiletime.
What do you think?
My 2 cents
type digit01 = '0' | '1';
type digit03 = digit01 | '2' | '3';
type digit05 = digit03 | '4' | '5';
type digit09 = digit05 | '6' | '7' | '8' | '9';
type minutes = `${digit05}${digit09}`;
type hour = `${digit01 | ''}${digit09}` | `2${digit03}`;
type MarkerTime = `${hour}:${minutes}`;
const ok: Record<string, MarkerTime> = {
a: '0:00',
b: '09:00',
c: '23:59',
};
const notOk: Record<string, MarkerTime> = {
a: '0-00',
b: '24:00',
c: '93.242:942.23',
};
Just to complement #bela53's answer, the use const assertions can be used for the type construction.
const hours = [
'00' , '01', '02', '03', '04', '05', '06', '07', '08',
'09' , '10', '11', '12', '13', '14', '15', '16',
'17' , '18', '19', '20', '21', '22', '23', '24'
] as const
type HH = typeof hours[number]
const minutes = [
'00', '01', '02', '03', '04', '05', '06', '07', '08', '09',
'10', '11', '12', '13', '14', '15', '16', '17', '18', '19',
'20', '21', '22', '23', '24', '25', '26', '27', '28', '29',
'30', '31', '32', '33', '34', '35', '36', '37', '38', '39',
'40', '41', '42', '43', '44', '45', '46', '47', '48', '49',
'50', '51', '52', '53', '54', '55', '56', '57', '58', '59'
] as const
type MM = typeof minutes[number]
type Time = `${HH}:${MM}`
I've been trying out RethinkDB for a while and i still don't know how to do something like this MongoDB example:
https://docs.mongodb.com/manual/tutorial/map-reduce-examples/#calculate-order-and-total-quantity-with-average-quantity-per-item
In Mongo, in the map function, I could iterate over an array field of one document, and emit multiple values.
I don't know how to set the key to emit in map or return more than one value per document in the map function.
For example, i would like to get from this:
{
'num' : 1,
'lets': ['a','b,'c']
}
to
[
{'num': 1, 'let' : 'a' },
{'num': 1, 'let' : 'b' },
{'num': 1, 'let' : 'c' }
]
I'm not sure if I should think this differently in RethinkDB or use something different from map-reduce.
Thanks.
I'm not familiar with Mongo; addressing your transformation example directly:
r.expr({
'num' : 1,
'lets': ['a', 'b', 'c']
})
.do(function(row) {
return row('lets').map(function(l) {
return r.object(
'num', row('num'),
'let', l
)
})
})
You can, of course, use map() instead of do() (in case not a singular object)
I'm trying use ConfigParser with setting of some default values. I know how to set those default values but having trouble with integers.
Here is my code:
import ConfigParser
defaults = {
"str1": "val1",
"str2": "val2",
"int1": 10,
"int2": 20
}
section = "some_section"
config = ConfigParser(defaults)
print config.get(section, "str1")
print config.get(section, "str1")
print config.getint(section, "int1")
print config.getint(section, "int2")
The default values works fine when some of the string values are not being provided.
But, when some of the integers values are not provided and the default value need to be used, exception of TypeError: argument of type 'int' is not iterable being thrown
I didn't found any example of integers as default values. Any help?
So, during my tests I found some interesting stuff.
One of them is that default value for integers and booleans need to be set as strings in the default dictionary (except for None values):
defaults = {
"str1": "val1",
"str2": "val2",
"int1": "10",
"int2": "20",
"boolean1": "True",
"boolean2": "False",
"empty_var": None
}
Note: to extract booleans use ConfigParser.getboolean
Now it works ;)