【问题标题】:Python for creating a set operations Calculator用于创建集合操作计算器的 Python
【发布时间】:2015-07-17 02:31:25
【问题描述】:

我正在尝试创建一个计算器,不是用于数字,而是用于集合运算。 为了说明这个概念,假设您有一个包含两列的文件。

keyword, userid
hello  , john
hello  , alice
world  , alice
world  , john
mars   , john
pluto  , dave

目标是读入类似的表达式

[hello]

并返回具有该关键字的用户集。例如

[hello]           -> ['john','alice']
[world] - [mars]  -> ['alice'] // the - here is for the difference operation
[world] * [mars]  -> ['john','alice'] // the * here is for the intersection operation
[world] + [pluto] -> ['john','alice','dave'] // the + here is for union operation

我使用python中的plyplus模块生成以下语法来解析这个需求。语法如下图

 Grammar("""
 start: tprog ;
 @tprog: atom | expr u_symbol expr | expr i_symbol expr | expr d_symbol | expr | '\[' tprog '\]';
 expr:   atom | '\[' tprog '\]';
 @atom: '\[' queryterm '\]' ;
 u_symbol: '\+' ;
 i_symbol: '\*' ;
 d_symbol: '\-' ;
 queryterm: '[\w ]+' ;

 WS: '[ \t]+' (%ignore);
 """)

但是,我无法在网络上找到任何好的链接来将解析后的输出提升到下一个级别,我可以逐步评估解析后的输出。我知道我需要将它解析为某种语法树并定义函数以递归地应用于每个节点及其子节点。任何帮助表示赞赏。

【问题讨论】:

  • 以下是为python中的算术表达式创建递归下降解析器。大概,您可以简单地定义自己的语法/标记? blog.erezsh.com/…
  • 我已经浏览过那个网站,但是很难将算术运算映射到集合运算

标签: python parsing grammar ply python-plyplus


【解决方案1】:

我是初学者,但我试图解决你的问题,如果我的回答有错误,请见谅。我建议使用 pandas,我认为它在这种情况下效果最好。

首先将数据保存在一个csv文件中

然后

from pandas import *

下一行是读取文件并将其转换为数据帧

x=read_csv('data.csv')
print(x)

结果

 keyword  userid
0  hello      john
1  hello     alice
2  world     alice
3  world      john
4  mars       john
5  pluto      dave

在下一行,我们将过滤数据框并将其分配给一个新变量

y= x[x['keyword'].str.contains("hello")]

其中关键字是感兴趣的列,hello 是我们要搜索的内容 结果

  keyword  userid
0  hello      john
1  hello     alice

我们只对第二列感兴趣,所以我们将使用索引来获取它,然后将它保存在一个新变量中

z=y.iloc[:,1]
print(z)

结果

0      john
1     alice

现在最后一步是使用将数据框转换为列表

my_list = z.tolist()

print(my_list)

结果

[' john', ' alice']

我认为您只需操作结果列表即可实现所需的功能

更新: 我试图解决你有“或”的情况 代码变成了这样

from pandas import *

x=read_csv('data.csv')
print(x)
y= x[x['keyword'].str.contains("hello|pluto")]
print(y)

z=y.iloc[:,1]
print(z)
my_list = z.tolist()

print(my_list)

结果

[' john', ' alice', ' dave']

更新2: 我找到了“-”和“*”情况的解决方案 首先,我们对两个词使用相同的代码

from pandas import *

x=read_csv('data.csv')
print(x)
y= x[x['keyword'].str.contains("world")]
print(y)

z=y.iloc[:,1]
print(z)
my_list = z.tolist()

print(my_list)
s= x[x['keyword'].str.contains("mars")]
print(s)

g=s.iloc[:,1]
print(g)
my_list2 = g.tolist()

print(my_list2)

然后我们添加一个循环两个减去两个列表

for i in my_list:
    if i in my_list2:
        my_list.remove(i)
print(my_list)

结果

[' alice']

而对于交叉点,只需更改最后一位

for i in my_list:
    if i not in  my_list2:
        my_list.remove(i)
print(my_list)

结果

[' john']

【讨论】:

  • 感谢您的意见。但是 pandas 在这里不起作用,尽管它适用于我提到的情况。我需要像语言一样扩展它,所以它必然有很多嵌套条件。见问题下的 cmets
【解决方案2】:

好的,这是我整理的一个 Java 实现,只是为了好玩。它本质上是对输入进行标记,然后使用调车场算法来评估标记。

请注意,老实说,我并不是 100% 确定它是否适用于复杂表达式 re:运算符优先级、操作顺序等。

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Scanner;

@SuppressWarnings("unchecked")
class Setop {

    public static void main(String[] args) {
        (new Setop()).run();
    }

    private HashMap<String, HashSet<String>> sets;

    private void run() {
        // Read file to initialise sets
        Scanner fin;
        try {
            fin = new Scanner(new File("data"));
        } catch (FileNotFoundException ex) {
            System.out.println("Cannot find data file");
            return;
        }
        sets = new HashMap<String, HashSet<String>>();
        fin.nextLine();
        while (fin.hasNextLine()) {
            String[] l = fin.nextLine().split(",");
            if (l.length == 2) {
                String k = "[" + l[0].trim() + "]";
                String v = l[1].trim();
                if (sets.get(k) == null) {
                    sets.put(k, new HashSet<String>());
                }
                sets.get(k).add(v);
            }
        }
        for (Entry<String, HashSet<String>> e : sets.entrySet()) {
            System.out.print(e.getKey() + ": ");
            for (String s : e.getValue())
                System.out.print(s + ", ");
            System.out.println();
        }
        // Main input/evaluation loop
        Scanner in = new Scanner(System.in);
        while (true) {
            System.out.print("> ");
            String sin = in.nextLine();
            if (sin.trim().equals("")) {
                return;
            }
            evaluate(sin);
        }
    }

    private void evaluate(String sin)
    {
        // Tokenize
        ArrayDeque<String> tokens = new ArrayDeque<String>();
        Matcher m = Pattern.compile(" *((\\[[a-z]+\\])|\\+|\\*|\\-|\\(|\\)) *").matcher(sin);
        int i = 0;
        while (m.find()) {
            if (m.start() != i) {
                System.out.println("Cannot tokenise at pos " + i);
                return;
            }
            i = m.end();
            tokens.add(m.group().trim());
        }
        if (i != sin.length()) {
            System.out.println("Cannot tokenise at pos " + i);
            return;
        }
        // Shunting yard algorithm to evaluate
        ArrayDeque<HashSet<String>> output = new ArrayDeque<HashSet<String>>();
        ArrayDeque<String> operators = new ArrayDeque<String>();
        for (String token : tokens) {
            if (Pattern.matches("\\[[a-z]+\\]", token)) {
                HashSet<String> s = sets.get(token);
                if (s == null) {
                    System.out.println("Cannot find set " + token);
                    return;
                }
                output.push((HashSet<String>)s.clone());
            } else if (Pattern.matches("\\+|\\*|\\-", token)
                || token.equals("(")) {
                operators.push(token);
            } else if (token.equals(")")) {
                while (operators.size() > 0
                    && Pattern.matches("\\+|\\*|\\-", operators.peek())) {
                    if (output.size() < 2) {
                        System.out.println("Cannot evaluate, excess operations");
                        return;
                    }
                    output.push(operate(operators.pop(), output.pop(), output.pop()));
                }
                if (operators.size() == 0
                    || !operators.pop().equals("(")) {
                        System.out.println("Cannot evaluate, unmatched parenthesis");
                        return;
                }
            } else {
                System.out.println("Cannot evaluate, unknown token " + token);
                return;
            }
        }
        while (operators.size() > 0) {
            if (operators.peek().equals("(")) {
                System.out.println("Cannot evaluate, unmatched parenthesis");
                return;
            }
            if (output.size() < 2) {
                System.out.println("Cannot evaluate, excess operations");
                return;
            }
            output.push(operate(operators.pop(), output.pop(), output.pop()));
        }
        if (output.size() != 1) {
            System.out.println("Cannot evaluate, excess operands");
            return;
        }
        for (String s : output.pop()) {
            System.out.print(s + ", ");
        }
        System.out.println();
    }

    private HashSet<String> operate(String op, HashSet<String> b, HashSet<String> a) {
        if (op.equals("+")) {
            // Union
            a.addAll(b);
        } else if (op.equals("*")) {
            // Intersection
            a.retainAll(b);
        } else {
            // Difference
            a.removeAll(b);
        }
        return a;
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多