【发布时间】:2021-03-24 15:57:17
【问题描述】:
给定一个本地宏,其中包含由逗号 (",") 或 逗号加空格(“,”)甚至只有空格(“”),有没有简单的方法可以提取第一个N 这个本地宏的级别(或单词)?
字符串看起来像"12, 123, 1321, 41"、"12,123,1321,41" 或"12 123 1321 41"。
基本上我会对 Macro Function word # of string 的一个版本感到满意
或多或少会像word 1/N of string 一样工作。 (参见“用于解析的宏函数”
pg 12 in Macro definition and manipulation)
有关更多上下文,我正在使用levelsof, local() sep() 的输出。所以
我可以选择更容易使用的分隔符。我想要
将结果级别作为参数传递给inlist() 函数。以下
通常有效,但inlist() 最多只需要 250 个参数。这就是为什么我会
喜欢从levelsof()的结果中提取250个单词的块
sysuse auto, clear
levelsof mpg if trunk > 20, local(levels) sep(", ")
list if inlist(mpg, `levels')
到目前为止的“解决方案”
我想出了一个不简单的方法来实现这一点,但它看起来并不好,而且 我想知道是否有一种简单的内置方法可以做到这一点。
sysuse auto, clear
levelsof mpg if trunk > 20, local(levels) sep(", ")
scalar number_of_words = 3
forvalues i = 1 (1) `=number_of_words' {
local word_i = `i'
local this_level : word `word_i' of `levels'
local list_of_levels = "`list_of_levels'`this_level'"
di as text "loop: `i'"
di as text "this level: `this_level'"
di as text "list of levels so far: `list_of_levels'"
}
di "`list_of_levels'"
// trim trailing comma
local trimmed_list_of_levels = substr( "`list_of_levels'" , 1 , strlen( "`list_of_levels'" )-1)
di "`trimmed_list_of_levels'"
list make mpg price trunk if inlist(mpg, `trimmed_list_of_levels')
输出
. sysuse auto, clear
(1978 Automobile Data)
.
. levelsof mpg if trunk > 20, local(levels) sep(", ")
12, 15, 17, 18
. scalar number_of_words = 3
. forvalues i = 1 (1) `=number_of_words' {
2. local word_i = `i'
3. local this_level : word `word_i' of `levels'
4. local list_of_levels = "`list_of_levels'`this_level'"
5.
. di as text "loop: `i'"
6. di as text "this level: `this_level'"
7. di as text "list of levels so far: `list_of_levels'"
8. }
loop: 1
this level: 12,
list of levels so far: 12,
loop: 2
this level: 15,
list of levels so far: 12,15,
loop: 3
this level: 17,
list of levels so far: 12,15,17,
.
. di "`list_of_levels'"
12,15,17,
.
. // trim trailing comma
. local trimmed_list_of_levels = substr( "`list_of_levels'" , 1 , strlen( "`list_of_levels'" )-1)
.
. di "`trimmed_list_of_levels'"
12,15,17
. list make mpg price trunk if inlist(mpg, `trimmed_list_of_levels')
+------------------------------------------+
| make mpg price trunk |
|------------------------------------------|
2. | AMC Pacer 17 4,749 11 |
5. | Buick Electra 15 7,827 20 |
23. | Dodge St. Regis 17 6,342 21 |
26. | Linc. Continental 12 11,497 22 |
27. | Linc. Mark V 12 13,594 18 |
|------------------------------------------|
31. | Merc. Marquis 15 6,165 23 |
53. | Audi 5000 17 9,690 15 |
74. | Volvo 260 17 11,995 14 |
+------------------------------------------+
与 cmets 相关的编辑。
编辑 01)
例如,以下内容不起作用。它返回错误130 expression too long。
clear
set obs 1000
gen id = _n
gen x1 = rnormal()
sum *
levelsof id if x1>0, local(levels) sep(", ")
sum * if inlist(id, `levels')
这种构造(levelsof + inlist)似乎是必要的示例
clear
set obs 5000
gen id = round(_n/5)
gen x1 = rnormal()
sum *
levelsof id if x1>2, local(levels) sep(", ")
sum * if x1>2 // if threshold is small enough, there will be too many values for inlist()
sum * if inlist(id, `levels')
【问题讨论】:
-
您可以在循环中使用
word命令,其中word将返回列表中的第n 个单词(请参阅help word)。您能否详细说明您对inlist的最终计划是什么?可能有更简单的方法。 -
感谢您的快速回复。请参阅问题中的编辑 1。如果有超过(大约)250 个级别,函数 inlist 返回
error 130``expression too long。当少于那个时,它工作正常。word函数只从字符串中检索一个单词。如果有一个用于检索n第一个单词s 的内置函数可以避免使用我在问题中写的那个循环,我就在徘徊。但是,如果没有内置或更简单的方法,则循环确实有效。 -
快速解答:将本地推入 Mata 并使用
tokens()的结果。 -
尼克的回答最适合您的要求。从我的角度来看,很难看到与您的编辑 1 相关的
sum * if x1>0的最终目标。 -
没错,我将添加一个示例,说明走这条路会有所不同。想象一下,我对相同的
id进行了多次观察,但不一定与相同的x1相同。如果我想提取至少有一次x1大于阈值的ids 的所有观察结果(以前和过去),那么据我所知,我需要求助于@987654350 @+inlist建设。
标签: string stata local-variables stata-macros