Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
63 views
in Technique[技术] by (71.8m points)

Union/Intersection for Dart Lists

In a Flutter app for iOS/Android that I am writing one of the tasks I need the app to handle is that of subscribing/unsubscribing the app to/from multiple Push notification topics as the user's behavior/location or other conditions change.

In itself this is not such a big issue. I am using the excellent Firebase Cloud Messaging plugin for this purpose and its subscribeToTopic + unSubscribeFromTopic methods do just what I need. However, there do not appear to be plural versions of these methods - I mean subscribeToTopic*s* and unSubscribeFromTopic*s*.

Doing a wholesale unsubscribeFrom for each currently subscribed topic followed by a subscribeTo... when ony a few of the topics have changed strikes me as being inefficient. So here is what I do instead

void performUnSubscribe(shared,e){if (!shared.contains(e)) print('Unsubscribe from $e');}

void performSubscribe(shared,e){if (!shared.contains(e)) print('Subscribe to $e');}

void main() 
{
 List<List<String>> topics = [
                              ['X311','Y739','C0','V1','x43','y5','D3179'],
                              //currently subscribed list of topics
                              ['X319','Y732','C0','V1','x43','y5','D3183']
                              //new list of topics to be subscribed to
                         ];

 List<String> shared = List.from(topics.fold<Set>(topics.first.toSet(),(a, b) => 
 a.intersection(b.toSet())));
                                  
 print(shared);
 print(topics);
 topics[0].forEach((e)=> performUnSubscribe(shared,e));
 topics[1].forEach((e)=> performSubscribe(shared,e));
}

which works and yields the output

Unsubscribe from X311
Unsubscribe from Y739
Unsubscribe from D3179
Subscribe to X319
Subscribe to Y732
Subscribe to D3183

While this works I find the code rather clumsy. Is there a better way of accomplishing the same result?

question from:https://stackoverflow.com/questions/66060782/union-intersection-for-dart-lists

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I am properly misunderstanding your problem but it seems you can achieve the same output by doing this:

void performUnSubscribe(String e) => print('Unsubscribe from $e');
void performSubscribe(String e) => print('Subscribe to $e');

void main() {
  final topics = [
    ['X311', 'Y739', 'C0', 'V1', 'x43', 'y5', 'D3179'],
    //currently subscribed list of topics
    ['X319', 'Y732', 'C0', 'V1', 'x43', 'y5', 'D3183']
    //new list of topics to be subscribed to
  ];

  topics[0]
      .where((element) => !topics[1].contains(element))
      .forEach(performUnSubscribe);
  topics[1]
      .where((element) => !topics[0].contains(element))
      .forEach(performSubscribe);
}

If your lists are containing a lot of elements, it can be more efficient to use a Set like you are already doing. So it would look like this:

void performUnSubscribe(String e) => print('Unsubscribe from $e');
void performSubscribe(String e) => print('Subscribe to $e');

void main() {
  final topics = [
    ['X311', 'Y739', 'C0', 'V1', 'x43', 'y5', 'D3179'],
    //currently subscribed list of topics
    ['X319', 'Y732', 'C0', 'V1', 'x43', 'y5', 'D3183']
    //new list of topics to be subscribed to
  ];

  var set = topics[1].toSet();
  topics[0]
      .where((element) => !set.contains(element))
      .forEach(performUnSubscribe);

  set = topics[0].toSet();
  topics[1]
      .where((element) => !topics[0].contains(element))
      .forEach(performSubscribe);
}

Or put the logic inside its own method like this:

void performUnSubscribe(String e) => print('Unsubscribe from $e');
void performSubscribe(String e) => print('Subscribe to $e');

void main() {
  final topics = [
    ['X311', 'Y739', 'C0', 'V1', 'x43', 'y5', 'D3179'],
    //currently subscribed list of topics
    ['X319', 'Y732', 'C0', 'V1', 'x43', 'y5', 'D3183']
    //new list of topics to be subscribed to
  ];

  runFunctionOnDifference(topics[0], topics[1], performUnSubscribe);
  runFunctionOnDifference(topics[1], topics[0], performSubscribe);
}

/// Execute [function] on elements in [list1] which are not on [list2].
void runFunctionOnDifference<T>(
    List<T> list1, List<T> list2, void Function(T) function) {
  final set = list2.toSet();
  list1.where((element) => !set.contains(element)).forEach(function);
}

All three solutions gives:

Unsubscribe from X311
Unsubscribe from Y739
Unsubscribe from D3179
Subscribe to X319
Subscribe to Y732
Subscribe to D3183

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...